<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="renderer" content="webkit"><meta name="format-detection" content="telephone=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="icon" href="/images/icons/favicon-16x16.png?v=2.0.0-rc.0" type="image/png" sizes="16x16"><link rel="icon" href="/images/icons/favicon-32x32.png?v=2.0.0-rc.0" type="image/png" sizes="32x32"><meta name="description" content="一、环境准备        linux系统，本人使用的是centos8，最小化安装 Redis下载">
<meta property="og:type" content="article">
<meta property="og:title" content="Redis学习">
<meta property="og:url" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/index.html">
<meta property="og:site_name" content="孙宇的博客">
<meta property="og:description" content="一、环境准备        linux系统，本人使用的是centos8，最小化安装 Redis下载">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/1.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/2.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/3.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/4.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/5.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/6.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/13.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/14.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/15.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/16.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/17.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/18.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/7.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/9.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/8.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/10.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/12.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/19.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/20.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/21.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/22.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/23.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/24.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/28.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/25.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/26.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/27.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/29.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/30.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/31.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/32.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/33.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/34.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/35.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/41.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/42.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/36.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/37.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/38.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/39.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/40.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/44.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/45.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/91.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/46.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/47.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/48.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/49.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/50.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/51.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/52.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/53.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/54.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/55.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/56.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/57.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/58.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/59.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/62.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/60.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/61.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/63.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/64.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/65.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/66.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/67.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/68.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/69.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/70.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/71.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/72.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/73.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/74.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/75.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/76.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/77.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/78.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/79.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/80.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/81.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/82.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/83.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/84.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/85.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/86.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/87.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/88.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/89.png">
<meta property="og:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/90.png">
<meta property="article:published_time" content="2021-08-06T11:49:29.000Z">
<meta property="article:modified_time" content="2021-09-26T15:03:31.222Z">
<meta property="article:author" content="孙宇">
<meta property="article:tag" content="Redis">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/1.png"><meta name="keywords" content="孙宇, 孙宇的博客"><meta name="description" content=""><title>Redis学习 | 孙宇的博客</title><link ref="canonical" href="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css" type="text/css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@latest/dist/gitalk.min.css" type="text/css"><link rel="stylesheet" href="/css/index.css?v=2.0.0-rc.0"><script>var Stun = window.Stun || {};
var CONFIG = {
  root: '/',
  algolia: undefined,
  fontIcon: {"prompt":{"success":"fas fa-check-circle","info":"fas fa-arrow-circle-right","warning":"fas fa-exclamation-circle","error":"fas fa-times-circle"},"copyBtn":"fas fa-copy"},
  sidebar: {"offsetTop":"20px","tocMaxDepth":6},
  header: {"enable":true,"showOnPost":true,"scrollDownIcon":true},
  postWidget: {"endText":true},
  nightMode: {"enable":true},
  back2top: {"enable":true},
  codeblock: {"style":"default","highlight":"light","wordWrap":false},
  reward: false,
  fancybox: false,
  zoomImage: {"gapAside":"20px"},
  galleryWaterfall: undefined,
  lazyload: false,
  pjax: undefined,
  externalLink: {"icon":{"enable":true,"name":"fas fa-external-link-alt"}},
  shortcuts: {"switchPost":true},
  prompt: {"copyButton":"复制","copySuccess":"复制成功","copyError":"复制失败"},
  sourcePath: {"js":"js","css":"css","images":"images"},
};

window.CONFIG = CONFIG;</script><meta name="generator" content="Hexo 5.0.2"></head><body><div class="container" id="container"><header class="header" id="header"><div class="header-inner"><nav class="header-nav header-nav--fixed"><div class="header-nav-inner"><div class="header-nav-menubtn"><i class="fas fa-bars"></i></div><div class="header-nav-menu"><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/"><span class="header-nav-menu-item__icon"><i class="fas fa-home"></i></span><span class="header-nav-menu-item__text">首页</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/archives/"><span class="header-nav-menu-item__icon"><i class="fas fa-folder-open"></i></span><span class="header-nav-menu-item__text">归档</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/categories/"><span class="header-nav-menu-item__icon"><i class="fas fa-layer-group"></i></span><span class="header-nav-menu-item__text">分类</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/tags/"><span class="header-nav-menu-item__icon"><i class="fas fa-tags"></i></span><span class="header-nav-menu-item__text">标签</span></a></div></div><div class="header-nav-search"><span class="header-nav-search__icon"><i class="fas fa-search"></i></span><span class="header-nav-search__text">搜索</span></div><div class="header-nav-mode"><div class="mode"><div class="mode-track"><span class="mode-track-moon"></span><span class="mode-track-sun"></span></div><div class="mode-thumb"></div></div></div></div></nav><div class="header-banner"><div class="header-banner-info"><div class="header-banner-info__title">孙宇的博客</div><div class="header-banner-info__subtitle">博客小白，正在学习中。如果有更好的意见欢迎反馈。</div></div><div class="header-banner-arrow"><div class="header-banner-arrow__icon"><i class="fas fa-angle-down"></i></div></div></div></div></header><main class="main" id="main"><div class="main-inner"><div class="content-wrap" id="content-wrap"><div class="content" id="content"><!-- Just used to judge whether it is an article page--><div id="is-post"></div><div class="post"><header class="post-header"><h1 class="post-title">Redis学习</h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-08-06</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-09-26</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">15.2k</span></span></div></header><div class="post-body">
        <h1 id="一、环境准备">
          <a href="#一、环境准备" class="heading-link"><i class="fas fa-link"></i></a>一、环境准备</h1>
      <ul>
<li>linux系统，本人使用的是centos8，最小化安装</li>
<li><span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://download.redis.io/releases/redis-6.2.5.tar.gz?_ga=2.264706890.49166100.1628230335-321395705.1628230335">Redis下载</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></li>
</ul>
<a id="more"></a>


        <h1 id="二、安装">
          <a href="#二、安装" class="heading-link"><i class="fas fa-link"></i></a>二、安装</h1>
      <ol>
<li><p>首先通过 <strong>tar -zxvg xxxxx</strong> 将 <strong>Redis</strong> 解压，目录随意，本人是在 <strong>/usr/local/</strong> 下创建了一个文件夹用来安装使用</p>
</li>
<li><p>解压过后执行 <strong>make</strong> 命令编译，执行的时候会检测你的系统是否缺少依赖之类的，如果没问题会进行编译</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/1.png" alt="图片加载失败"></p>
</li>
<li><p>编译成功后，执行 <strong>make test</strong> 命令检测一下是否有什么错误</p>
<ul>
<li><p>小编这里就出现了错误</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/2.png" alt="图片加载失败"></p>
<p>这个错误的意思是：如果想要执行 <strong>make test</strong> 命令需要一个 <strong>tcl 8.5</strong> 的库，如果想要 <strong>test</strong> 就要安装这个库</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/3.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
<li><p>执行 <strong>make PREFIX /usr/local/redis install</strong> 安装， **PREFIX /usr/local/redis ** 为指定安装目录</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/4.png" alt="图片加载失败"></p>
<p>安装好之后则会在 <strong>/usr/local/redis</strong> 下生成 <strong>bin</strong> 文件夹，内含文件如下</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/5.png" alt="图片加载失败"></p>
<p>他们分别是：</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">redis-benchmark   #redis 性能测试工具</span><br><span class="line">redis-check-aof   #检查aof日志的工具</span><br><span class="line">redis-check-rdb   #检查rdb日志的工具</span><br><span class="line">redis-cli         #redis 连接的客户端</span><br><span class="line">redis-sentinel    #哨兵模式</span><br><span class="line">redis-server      #redis 服务进程</span><br></pre></td></tr></table></div></figure>


</li>
</ol>

        <h1 id="三、配置">
          <a href="#三、配置" class="heading-link"><i class="fas fa-link"></i></a>三、配置</h1>
      <ol>
<li><p>从源代码目录复制 <strong>redis.conf</strong> 文件到 <strong>bin</strong> 同级</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/6.png" alt="图片加载失败"></p>
</li>
<li><p>注释掉 <strong>bind</strong> 配置，如果不注释的话，默认只有 <strong>127.0.0.1</strong> 也就是本机可以连接</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/13.png" alt="图片加载失败"></p>
</li>
<li><p>保护模式设置，关闭保护模式，如果开启的话，redis只能本机访问</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/14.png" alt="图片加载失败"></p>
</li>
<li><p><strong>backlog</strong> 连接队列</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/15.png" alt="图片加载失败"></p>
</li>
<li><p>配置 <strong>redis</strong> 后台启动</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/16.png" alt="图片加载失败"></p>
</li>
<li><p>日志文件配置，默认为空，即在那个目录启动，日志文件就在那个目录下生成</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/17.png" alt="图片加载失败"></p>
</li>
<li><p>数据库个数</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/18.png" alt="图片加载失败"></p>
</li>
</ol>

        <h1 id="四、启动与连接">
          <a href="#四、启动与连接" class="heading-link"><i class="fas fa-link"></i></a>四、启动与连接</h1>
      <ol>
<li><p>显示启动 <strong>redis-server</strong> 服务</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 启动 bin 目录下的 redis-server，并指定使用我们刚才拷贝过来的 redis.conf 配置文件</span></span><br><span class="line">./bin/redis-server ./redis.conf</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/7.png" alt="图片加载失败"></p>
</li>
<li><p>隐式启动 <strong>redis-server</strong> 服务</p>
<p>修改 <strong>redis.conf</strong> 配置文件</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/9.png" alt="图片加载失败"></p>
</li>
<li><p>连接 <strong>redis-cli</strong> 客户端，并测试</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 启动客户端</span></span><br><span class="line">./bin.redis-cli</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 新增key-velue, 存储字符串 双引号 可有可无</span></span><br><span class="line">set word &quot;hello world&quot;</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 根据key查询</span></span><br><span class="line">get word</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/8.png" alt="图片加载失败"></p>
</li>
<li><p>关闭</p>
<ul>
<li><p>显示启动的 <strong>redis-server</strong> 直接按 <strong>ctrl + c</strong> 即可</p>
</li>
<li><p>隐式启动的 <strong>redis-server</strong> 需要查询到进程后，根据进程ID杀死进程即可</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/10.png" alt="图片加载失败"></p>
</li>
<li><p>关闭 <strong>redis-cli</strong> 输入 <strong>exit</strong> 即可</p>
</li>
</ul>
</li>
</ol>

        <h1 id="五、操作命令">
          <a href="#五、操作命令" class="heading-link"><i class="fas fa-link"></i></a>五、操作命令</h1>
      <p>在操作之前我们先要知道：</p>
<ol>
<li><strong>redis</strong> 中都有哪些数据类型：<strong>string、list、set、zset(order set)、hash</strong></li>
<li><strong>redis</strong> 中共有16个数据库（空间），使用<strong>select 0</strong> 切换，默认使用 0号库</li>
</ol>

        <h2 id="1、基础操作">
          <a href="#1、基础操作" class="heading-link"><i class="fas fa-link"></i></a>1、基础操作</h2>
      
        <h3 id="1）新增">
          <a href="#1）新增" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h3>
      <ol>
<li><p>字符串（string）</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> key value</span></span><br><span class="line">set site www.baidu.com</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>追加</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 向指定的 key 追加值，如果key不存在则创建并返回value长度，如果存在则向value后追加，并返回追加后的value长度</span></span><br><span class="line">append key value</span><br></pre></td></tr></table></div></figure>



</li>
</ol>

        <h3 id="2）删除">
          <a href="#2）删除" class="heading-link"><i class="fas fa-link"></i></a>2）删除</h3>
      <ol>
<li><p>字符串（string）</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 单个 del key</span></span><br><span class="line">del site</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">批量删除</span></span><br><span class="line">del sit age</span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h3 id="3）修改">
          <a href="#3）修改" class="heading-link"><i class="fas fa-link"></i></a>3）修改</h3>
      <ol>
<li><p>字符串（string）</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 修改值 <span class="built_in">set</span> key value</span></span><br><span class="line">set site www.baidu.com</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">修改 key 名称，如果修改后的key name 存在，则会覆盖修改后的key name 的值</span></span><br><span class="line">rename age agee</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">修改 key 名称，检查修改后的key name是否存在，如果不存在返回1，表示成功，否则返回0，修改不成功</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> nx: not exists 是否存在</span></span><br><span class="line">renamenx age site </span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h3 id="4）查询">
          <a href="#4）查询" class="heading-link"><i class="fas fa-link"></i></a>4）查询</h3>
      <ol>
<li><p>字符串（string）</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> get key</span></span><br><span class="line">get site</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询并修改</span></span><br><span class="line">getset site test</span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h3 id="5）各种查询">
          <a href="#5）各种查询" class="heading-link"><i class="fas fa-link"></i></a>5）各种查询</h3>
      <ol>
<li><p><strong>*</strong> 的使用</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查询所有key</span></span><br><span class="line">keys *</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 模糊匹配</span></span><br><span class="line">keys si*</span><br></pre></td></tr></table></div></figure>
</li>
<li><p><strong>[]</strong> 的使用</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 比较精确的匹配，匹配中括号中的字符</span></span><br><span class="line">keys sit[ey]</span><br></pre></td></tr></table></div></figure>
</li>
<li><p><strong>？</strong>的使用</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ? 匹配单个字符</span></span><br><span class="line">keys si?e</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>随机返回一个key</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">randomkey</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>查看 <strong>key</strong> 的类型：</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">type</span> key</span></span><br><span class="line">type site</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>查看某个 <strong>key</strong> 是否存在：</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 存在返回 1，不存在返回 0</span></span><br><span class="line">exists site</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>获取 <strong>value</strong> 的长度</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">strlen key</span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h3 id="6）key-移动">
          <a href="#6）key-移动" class="heading-link"><i class="fas fa-link"></i></a>6）key 移动</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 将 key 移动至1号库</span></span><br><span class="line">move site 1</span><br></pre></td></tr></table></div></figure>


        <h3 id="7-）key-递增-减">
          <a href="#7-）key-递增-减" class="heading-link"><i class="fas fa-link"></i></a>7 ）key 递增/减</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 设置整型 key，每次递增 1</span></span><br><span class="line">incr key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置整型 key，每次递减 1</span></span><br><span class="line">decr key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置整型 key，递增10，即步长</span></span><br><span class="line">incrby key 10</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 浮点数类型 递增，没有相应的递减</span></span><br><span class="line">incrbyfloat key 1.1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">设置整型 key，递减10，即步长</span></span><br><span class="line">decrby key 10</span><br></pre></td></tr></table></div></figure>




        <h3 id="8）key-的生命周期">
          <a href="#8）key-的生命周期" class="heading-link"><i class="fas fa-link"></i></a>8）key 的生命周期</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 查询key的有效期</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 已过期/不过期的key 返回-1，Redis2.8后不存在的key 返回-2</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 返回 秒</span></span><br><span class="line">ttl site</span><br><span class="line"><span class="meta">#</span><span class="bash"> 返回 毫秒</span></span><br><span class="line">pttl site</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置key的生命周期</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 秒</span></span><br><span class="line">expire site 10</span><br><span class="line"><span class="meta">#</span><span class="bash"> 毫秒</span></span><br><span class="line">pexpire site 10000</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置key永久有效</span></span><br><span class="line">persist key</span><br></pre></td></tr></table></div></figure>


        <h3 id="9）切换数据库，默认有16个">
          <a href="#9）切换数据库，默认有16个" class="heading-link"><i class="fas fa-link"></i></a>9）切换数据库，默认有16个</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select 0</span><br></pre></td></tr></table></div></figure>


        <h3 id="10）清空数据库">
          <a href="#10）清空数据库" class="heading-link"><i class="fas fa-link"></i></a>10）清空数据库</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">flushdb</span><br></pre></td></tr></table></div></figure>


        <h2 id="2、各种数据类型的操作">
          <a href="#2、各种数据类型的操作" class="heading-link"><i class="fas fa-link"></i></a>2、各种数据类型的操作</h2>
      
        <h3 id="2-1、string（字符串）类型">
          <a href="#2-1、string（字符串）类型" class="heading-link"><i class="fas fa-link"></i></a>2-1、string（字符串）类型</h3>
      
        <h4 id="1）新增-1">
          <a href="#1）新增-1" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ex:设置生命周期秒数</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> px:设置生命周期毫秒数</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 生命周期设置ex/px同时写的时候以后面的有效期为准</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> nx:表示 key 不存在时，执行操作</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> xx:表示 key 存在时，执行操作</span></span><br><span class="line">set key value [ex 秒数][px 毫秒数] [nx]/[xx]</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 20 秒过期，value为10</span></span><br><span class="line">set age 20 10</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 一次性新增多个键值</span></span><br><span class="line">mset key value key value</span><br></pre></td></tr></table></div></figure>


        <h4 id="2）查询">
          <a href="#2）查询" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h4>
      <figure class="highlight plain"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">get key</span><br><span class="line"></span><br><span class="line"># 获取多个key</span><br><span class="line">mget key1 key2 key3</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）删除">
          <a href="#3）删除" class="heading-link"><i class="fas fa-link"></i></a>3）删除</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 单个 del key</span></span><br><span class="line">del site</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">批量删除</span></span><br><span class="line">del sit age</span><br></pre></td></tr></table></div></figure>


        <h4 id="4）偏移量">
          <a href="#4）偏移量" class="heading-link"><i class="fas fa-link"></i></a>4）偏移量</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 偏移 从下标位置向后替换</span></span><br><span class="line">setrange key index value</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> start,stop可以为负数，则是从value末尾开始，</span></span><br><span class="line">getrange key start stop</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/12.png" alt="图片加载失败"></p>

        <h3 id="2-2、list（列表）类型">
          <a href="#2-2、list（列表）类型" class="heading-link"><i class="fas fa-link"></i></a>2-2、list（列表）类型</h3>
      
        <h4 id="1）新增-2">
          <a href="#1）新增-2" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 从左侧推入</span></span><br><span class="line">lpush list a b c d</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 从右侧推入</span></span><br><span class="line">rpush list a b c d</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 插入值，在列表中找到某个值，并在其前或后插入值，如果没有找到则会返回 -1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果找到了多个值，则会在第一个找到的值前后插入值。</span></span><br><span class="line">linsert key after|before search value</span><br><span class="line">eg:</span><br><span class="line"><span class="meta">#</span><span class="bash"> 在key为num的列表中找到3，并在3的前面插入2</span></span><br><span class="line">linsert num before 3 2</span><br></pre></td></tr></table></div></figure>


        <h4 id="2）查询-1">
          <a href="#2）查询-1" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 范围取值</span></span><br><span class="line">lrange list 0 1</span><br><span class="line">lrange list 0 -1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 根据下标获取元素</span></span><br><span class="line">lindex list index</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取列表长度</span></span><br><span class="line">llen key</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）-删除（弹出）">
          <a href="#3）-删除（弹出）" class="heading-link"><i class="fas fa-link"></i></a>3） 删除（弹出）</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 删除整个key</span></span><br><span class="line">del key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 弹出元素</span></span><br><span class="line">lpop list</span><br><span class="line">rpop list</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 删除元素</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> count 删除几个，正数代表从左向右删除，负数代表从右向左删除</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> value 根据值删除</span></span><br><span class="line">lrem key count value</span><br><span class="line">eg: </span><br><span class="line">lrem list 1 value</span><br><span class="line">lrem list -1 value </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 等待弹出</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果key中没有元素，则等待有值了之后弹出</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> timeout 为0 则一直等待</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 适用场景：长轮询，在线聊天</span></span><br><span class="line">brpop/blpop key timeout</span><br></pre></td></tr></table></div></figure>


        <h4 id="4）剪切">
          <a href="#4）剪切" class="heading-link"><i class="fas fa-link"></i></a>4）剪切</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 剪切后key的值就变为剪切的值</span></span><br><span class="line">ltrim key start stop</span><br></pre></td></tr></table></div></figure>




        <h4 id="5）弹出并插入">
          <a href="#5）弹出并插入" class="heading-link"><i class="fas fa-link"></i></a>5）弹出并插入</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 在第一个列表的右侧弹出一个元素，并插入到第二个列表的左侧，成功会返回弹出插入的值</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 原子性操作</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 适用场景:</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 两个列表: task[a,b,c,d] bak[]</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 执行任务时可以使用此命令:task[a,b,c] bak[d],执行命令后会返回弹出并插入的值，也就是d</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这个时候我们就知道该执行任务：d</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果执行成功则在bak中，pop掉d</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果执行失败，或者没有执行，那么bak中的d还在。下次再执行任务的时候去bak中拿就好了。</span></span><br><span class="line">rpoplpush key1 key2</span><br></pre></td></tr></table></div></figure>


        <h3 id="2-3、set（集合）类型，无序">
          <a href="#2-3、set（集合）类型，无序" class="heading-link"><i class="fas fa-link"></i></a>2-3、set（集合）类型，无序</h3>
      
        <h4 id="1）新增-3">
          <a href="#1）新增-3" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sadd key value1 value2 ...</span><br></pre></td></tr></table></div></figure>


        <h4 id="2）查询-2">
          <a href="#2）查询-2" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 随机查询出一个元素，或指定count个元素</span></span><br><span class="line">srandmember key count</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询集合所有元素</span></span><br><span class="line">smembers key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 判断value是否包含在集合中，是返回1，否则返回0</span></span><br><span class="line">sismember key value </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询集合共有多少个元素</span></span><br><span class="line">scard key</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）删除（弹出）">
          <a href="#3）删除（弹出）" class="heading-link"><i class="fas fa-link"></i></a>3）删除（弹出）</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 删除元素(根据值删除)</span></span><br><span class="line">srem key value1 value2</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 弹出</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 随机删除一个元素并返回pop出的值，count可以指定随机删除多少个</span></span><br><span class="line">spop key count</span><br></pre></td></tr></table></div></figure>


        <h4 id="4）更多">
          <a href="#4）更多" class="heading-link"><i class="fas fa-link"></i></a>4）更多</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 删除指定集合重元素，并将删除的元素添加到另一个集合</span></span><br><span class="line">smove sourcr target value</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 交集</span></span><br><span class="line">sinter key1 key2 key3</span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询出交集并存储在一个key(targer)中</span></span><br><span class="line">sinterstore target key1 key2 key3</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 并集</span></span><br><span class="line">sunion key1 key2 key3</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 差集,key1 与 key2 key3 的差集,返回key1中存在，其他key中不存在的</span></span><br><span class="line">sdiff key1 key2 key3</span><br></pre></td></tr></table></div></figure>


        <h3 id="2-4、Hash（哈希）类型">
          <a href="#2-4、Hash（哈希）类型" class="heading-link"><i class="fas fa-link"></i></a>2-4、Hash（哈希）类型</h3>
      
        <h4 id="1）新增-4">
          <a href="#1）新增-4" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 单个，如果field已经存在则会覆盖原有的value</span></span><br><span class="line">hset key field value</span><br><span class="line">eg：</span><br><span class="line">hset user id 1</span><br><span class="line">hset user name zhangsan</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果key中field不存在，添加成功，否则添加失败</span></span><br><span class="line">hsetnx key field value</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 批量为key设置<span class="built_in">hash</span>值</span></span><br><span class="line">hmset key field1 value1 field2 value2</span><br></pre></td></tr></table></div></figure>


        <h4 id="2）查询-3">
          <a href="#2）查询-3" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 根据key的属性查询value</span></span><br><span class="line">hget key field</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询key中是否存在某个field</span></span><br><span class="line">hexists key field</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询key中所有的field</span></span><br><span class="line">hkeys key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询key中所有value</span></span><br><span class="line">hvals key</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）删除-1">
          <a href="#3）删除-1" class="heading-link"><i class="fas fa-link"></i></a>3）删除</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">del key</span><br></pre></td></tr></table></div></figure>


        <h4 id="4）更多-1">
          <a href="#4）更多-1" class="heading-link"><i class="fas fa-link"></i></a>4）更多</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 为key中field对应的value增加量操作，针对数字的value</span></span><br><span class="line">hincrby key field increment</span><br><span class="line">eg：</span><br><span class="line">hset user id 1</span><br><span class="line">hincrby user id 12</span><br><span class="line">result：13</span><br></pre></td></tr></table></div></figure>




        <h3 id="2-5、zset-order-set-有序集合">
          <a href="#2-5、zset-order-set-有序集合" class="heading-link"><i class="fas fa-link"></i></a>2-5、zset(order set) 有序集合</h3>
      
        <h4 id="1）新增-5">
          <a href="#1）新增-5" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 根据order排序</span></span><br><span class="line">zadd key order1 value1 order2 value2</span><br></pre></td></tr></table></div></figure>


        <h4 id="2）查询-4">
          <a href="#2）查询-4" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 把集合排序后，返回范围内数据[start，stop]</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 注意这里是先进行“排序”，在拿 start - stop(下标/排名)的值</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 默认升序</span></span><br><span class="line">zrange key start stop </span><br><span class="line"><span class="meta">#</span><span class="bash"> 降序</span></span><br><span class="line">zrevrange key start stop</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里也是和集合升序排序后取值，这里的min,max指的是实际排序的值</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">limit</span> 分页</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> offset 偏移量，从那个开始算</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> N 查多少个</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> withscores 实际分数</span></span><br><span class="line">zrangebyscorce key min max withscores limit offset N</span><br><span class="line">eg:</span><br><span class="line">zadd test 1 a 3 c 2 b 4 d 6 f 9 i 8 h</span><br><span class="line">zrangebyscore test 4 8 </span><br><span class="line"><span class="meta">#</span><span class="bash"> result：d f h</span></span><br><span class="line">zrangebyscore test 4 8 withscores</span><br><span class="line"><span class="meta">#</span><span class="bash"> result：d 4 f 6 h 8</span></span><br><span class="line">zrange test 4 8</span><br><span class="line"><span class="meta">#</span><span class="bash"> result：f h i</span></span><br><span class="line">zrangebyscore test 1 8 limit 1 2</span><br><span class="line"><span class="meta">#</span><span class="bash"> result：b c</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 先对集合生序排序，再查询value 在key中拍第几个，从0开始。</span></span><br><span class="line">zrank key value</span><br><span class="line"><span class="meta">#</span><span class="bash"> 降序</span></span><br><span class="line">zrevrank key value</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）删除-2">
          <a href="#3）删除-2" class="heading-link"><i class="fas fa-link"></i></a>3）删除</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 根据元素删除</span></span><br><span class="line">zrem key value</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 按排名删除（下标）</span></span><br><span class="line">zremrangebyrank test 0 1</span><br><span class="line">eg:</span><br><span class="line">zadd test 1 a 3 c 2 b 4 d 6 f 9 i 8 h</span><br><span class="line"><span class="meta">#</span><span class="bash"> 删除的就是： a b</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 按分数（排序实际的值）删除</span></span><br><span class="line">zremrangebyscore test 2 8 </span><br><span class="line">eg:</span><br><span class="line">zadd test 1 a 3 c 2 b 4 d 6 f 9 i 8 h</span><br><span class="line"><span class="meta">#</span><span class="bash"> 删除的就是: b c d f h</span></span><br></pre></td></tr></table></div></figure>


        <h4 id="4）-更多">
          <a href="#4）-更多" class="heading-link"><i class="fas fa-link"></i></a>4） 更多</h4>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 统计集合内一共有多少个</span></span><br><span class="line">zcard key</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 统计集合内指定范围内的</span></span><br><span class="line">zcount ket start stop</span><br></pre></td></tr></table></div></figure>


        <h1 id="六、发布和订阅">
          <a href="#六、发布和订阅" class="heading-link"><i class="fas fa-link"></i></a>六、发布和订阅</h1>
      
        <h2 id="1、什么是发布和订阅">
          <a href="#1、什么是发布和订阅" class="heading-link"><i class="fas fa-link"></i></a>1、什么是发布和订阅</h2>
      <ol>
<li><strong>Redis</strong> 发布订阅（<strong>pub/sub</strong>）是一种消息通信模式：发送者（<strong>pub</strong>）发送消息，订阅者（<strong>sub</strong>）订阅消息</li>
<li><strong>Redis</strong> 客户端可以订阅任意数量的频道</li>
</ol>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/19.png" alt="图片加载失败"></p>

        <h2 id="2、发布和订阅命令行示例">
          <a href="#2、发布和订阅命令行示例" class="heading-link"><i class="fas fa-link"></i></a>2、发布和订阅命令行示例</h2>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 分别打开三个四个窗体</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 前三个窗口用于订阅消息，最后一个用于发布消息</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 前三个窗口分别执行以下命令</span></span><br><span class="line">subscribe a1</span><br><span class="line">subscribe a2</span><br><span class="line">subscribe a1 a2</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 最后一个窗口执行以下命令</span></span><br><span class="line">publish a1 hello</span><br><span class="line">publish a2 world</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 最后查看前三个窗体分别接收到了那个消息</span></span><br></pre></td></tr></table></div></figure>

<p>订阅消息：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/20.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/21.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/22.png" alt="图片加载失败"></p>
<p>发布消息：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/23.png" alt="图片加载失败"></p>

        <h1 id="七、新数据类型">
          <a href="#七、新数据类型" class="heading-link"><i class="fas fa-link"></i></a>七、新数据类型</h1>
      
        <h2 id="1、Bitmaps（位操作）">
          <a href="#1、Bitmaps（位操作）" class="heading-link"><i class="fas fa-link"></i></a>1、Bitmaps（位操作）</h2>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 设置 key 偏移量的位置 是1/0</span></span><br><span class="line">setbit key offset value</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取 key 偏移量的位置的 值</span></span><br><span class="line">getbit key offset</span><br><span class="line"></span><br><span class="line">------------------------------------------------------------------</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取 key 开始-结束 有多少个1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里的 start，top指的是字节组</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 即 01000000 8个bit 为一个字节组</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> </span></span><br><span class="line">bitcount key start top</span><br><span class="line">eg：</span><br><span class="line">setbit a 1000 0</span><br><span class="line">setbit a 0 1</span><br><span class="line">setbit a 2 1</span><br><span class="line"><span class="meta">#</span><span class="bash"> a中的二进制，也就是 位 是： 10100000</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询所有，即返回a中bit为1的个数</span></span><br><span class="line">bitcount a </span><br><span class="line"></span><br><span class="line">setbit a 8 1</span><br><span class="line"><span class="meta">#</span><span class="bash"> a中的二进制，也就是 位 是：10100000 10000000</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里 start：0 指的就是：10100000</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里 end：1 指的就是： 10000000</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 这个返回 2</span></span><br><span class="line">bitcount a 0 0 </span><br><span class="line"><span class="meta">#</span><span class="bash"> 这个返回 3</span></span><br><span class="line">bitcount a 0 1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">------------------------------------------------------------------</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 多个key 按位操作 </span></span><br><span class="line"><span class="meta">#</span><span class="bash"> operation 可以是: AND OR NOT XOR</span></span><br><span class="line">bitop operation destkey key1 [key2...]</span><br><span class="line">eg:</span><br><span class="line">setbit lower 2 1</span><br><span class="line">set char Q</span><br><span class="line"><span class="meta">#</span><span class="bash"> char 和 lower 做or才操作，比较后 char的第二位变成了1 ，结果放在cahr上</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 第一个 char 表示放在那个key上</span></span><br><span class="line">bitop and lower char char lower</span><br></pre></td></tr></table></div></figure>


        <h2 id="2、HyperLogLog（基数统计）">
          <a href="#2、HyperLogLog（基数统计）" class="heading-link"><i class="fas fa-link"></i></a>2、HyperLogLog（基数统计）</h2>
      <p>什么是基数：假如现在有这么一组数据{1,3,5,7,5,7,8}， 那么他的基数就是{1,3,5,7,8}</p>

        <h3 id="1）新增-6">
          <a href="#1）新增-6" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pfadd key elements</span><br><span class="line">eg:</span><br><span class="line">pfadd program java php java</span><br><span class="line">result: java php</span><br></pre></td></tr></table></div></figure>


        <h3 id="2）查询-5">
          <a href="#2）查询-5" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 统计基数个数</span></span><br><span class="line">pfcount program </span><br><span class="line">result: 2</span><br></pre></td></tr></table></div></figure>


        <h3 id="3）更多">
          <a href="#3）更多" class="heading-link"><i class="fas fa-link"></i></a>3）更多</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 合并，将多个 key 的元素合并到一个目标 key 中</span></span><br><span class="line">pfmerge target keys</span><br><span class="line">eg:</span><br><span class="line">pfadd k1 a b</span><br><span class="line">pfmerge k2 program k1</span><br><span class="line">result: 4</span><br></pre></td></tr></table></div></figure>


        <h2 id="3、Geospatial（地理信息的缩写）">
          <a href="#3、Geospatial（地理信息的缩写）" class="heading-link"><i class="fas fa-link"></i></a>3、Geospatial（地理信息的缩写）</h2>
      <p>注：该类型就是元素的 2 维坐标。在地图上就是经纬度。<strong>redis</strong> 基于该类型，提供了经纬度设置，查询，范围查询，距离查询，经纬度 <strong>Hash</strong> 等操作.</p>

        <h3 id="1）新增-7">
          <a href="#1）新增-7" class="heading-link"><i class="fas fa-link"></i></a>1）新增</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">  经度 纬度 名称</span></span><br><span class="line">geoadd key longitude latitude member</span><br><span class="line">eg:</span><br><span class="line">geoadd china:city 121.47 31.23 shanghai 106.50 29.53 chongqing</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 两极无法直接添加，一般会下载城市数据，通过 java 程序一次性导入。</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。</span></span><br></pre></td></tr></table></div></figure>


        <h3 id="2）查询-6">
          <a href="#2）查询-6" class="heading-link"><i class="fas fa-link"></i></a>2）查询</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 获得指定地区的坐标值</span></span><br><span class="line">geopos key member</span><br><span class="line">eg:</span><br><span class="line">geopos china:city shanghai</span><br><span class="line">result:</span><br><span class="line">1) 121.47000163793563843  # 经度</span><br><span class="line">2) 31.22999903975783553   # 纬度</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取两位位置的直线距离</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> m 米 默认值</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> km 千米</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> mi 英里</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> ft 英尺</span></span><br><span class="line">geodist key member1 member2 [m|km|ft|mi]</span><br><span class="line">eg:</span><br><span class="line">geodist china:city shanghai chongqing</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询给定经纬度为中心，半径内的元素</span></span><br><span class="line">georadius key  longitude latitude radius [m|km|ft|mi]</span><br><span class="line">eg:</span><br><span class="line"><span class="meta">#</span><span class="bash"> 查询 key 中 经纬度为中心 1000 公里内的元素</span></span><br><span class="line">georadius china:city 110 30 1000 km</span><br></pre></td></tr></table></div></figure>


        <h1 id="八、Jedis-操作">
          <a href="#八、Jedis-操作" class="heading-link"><i class="fas fa-link"></i></a>八、Jedis 操作</h1>
      
        <h2 id="1、Jedis-连接测试">
          <a href="#1、Jedis-连接测试" class="heading-link"><i class="fas fa-link"></i></a>1、Jedis 连接测试</h2>
      <ol>
<li><p>创建一个 <strong>Maven</strong> 工程</p>
</li>
<li><p><strong>pom</strong> 文件中增加依赖</p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jedis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.6.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></div></figure>
</li>
<li><p>创建一个类并测试</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/24.png" alt="图片加载失败"></p>
</li>
<li><p>启动 <strong>main</strong> 方法</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/28.png" alt="图片加载失败"></p>
</li>
</ol>
<p><font color="red"><strong>注意：</strong></font>这里可能会发生报错，可能是由于虚拟机防火墙为关闭导致的</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/25.png" alt="图片加载失败"></p>
<p>关闭防火墙：</p>
<ol>
<li><p>执行 <strong>systemctl status firewalld</strong> 查看防火墙状态</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/26.png" alt="图片加载失败"></p>
</li>
<li><p>执行<strong>systemctl stop firewalld</strong> 关闭防火墙，在查看防火墙状态</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/27.png" alt="图片加载失败"></p>
</li>
<li><p>禁用防火墙：<strong>systemctl disable firewalld</strong></p>
</li>
</ol>

        <h2 id="2、测试相关数据类型">
          <a href="#2、测试相关数据类型" class="heading-link"><i class="fas fa-link"></i></a>2、测试相关数据类型</h2>
      <p><font color="red"><strong>注：</strong></font>因为和命令行操作相同，所以就不所有命令都进行测试了</p>

        <h3 id="1）String-类型">
          <a href="#1）String-类型" class="heading-link"><i class="fas fa-link"></i></a>1）String 类型</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 字符串类型测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line">    <span class="comment">// 单个 key-value 设置</span></span><br><span class="line">    jedis.set(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">    String name = jedis.get(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">    System.out.println(name);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 多个 key-value 设置</span></span><br><span class="line">    jedis.mset(<span class="string">&quot;age&quot;</span>, <span class="string">&quot;12&quot;</span>, <span class="string">&quot;sex&quot;</span>, <span class="string">&quot;man&quot;</span>);</span><br><span class="line">    List&lt;String&gt; keys = jedis.mget(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;age&quot;</span>, <span class="string">&quot;sex&quot;</span>);</span><br><span class="line">    System.out.println(keys);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取所有 key</span></span><br><span class="line">    Set&lt;String&gt; set = jedis.keys(<span class="string">&quot;*&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : set) &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;key：&quot;</span> + str);</span><br><span class="line">        String value = jedis.get(str);</span><br><span class="line">        System.out.println(<span class="string">&quot;value：&quot;</span> + value);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 判断 key 是否存在</span></span><br><span class="line">    System.out.println(jedis.exists(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">    <span class="comment">// 设置 key 过期时间，这里 expire 方法过期了，可以使用 JedisCommands 实现</span></span><br><span class="line">    jedis.expire(<span class="string">&quot;test_key&quot;</span>, <span class="number">30</span>);</span><br><span class="line">    <span class="comment">// 查看 key 的过期时间</span></span><br><span class="line">    System.out.println(jedis.ttl(<span class="string">&quot;test_key&quot;</span>));</span><br><span class="line">    </span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="2）List-类型">
          <a href="#2）List-类型" class="heading-link"><i class="fas fa-link"></i></a>2）List 类型</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * List 类型测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test_list</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line">    jedis.flushDB();</span><br><span class="line">    jedis.lpush(<span class="string">&quot;list&quot;</span>, <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>);</span><br><span class="line">    jedis.rpush(<span class="string">&quot;list&quot;</span>, <span class="string">&quot;c&quot;</span>);</span><br><span class="line"></span><br><span class="line">    String val1 = jedis.lindex(<span class="string">&quot;list&quot;</span>, <span class="number">1</span>);</span><br><span class="line">    System.out.println(val1);</span><br><span class="line"></span><br><span class="line">    List&lt;String&gt; list = jedis.lrange(<span class="string">&quot;list&quot;</span>, <span class="number">0</span>, -<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : list) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="3）Set-类型">
          <a href="#3）Set-类型" class="heading-link"><i class="fas fa-link"></i></a>3）Set 类型</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * set 类型测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test_set</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line">    jedis.flushDB();</span><br><span class="line">    jedis.sadd(<span class="string">&quot;set&quot;</span>, <span class="string">&quot;set1&quot;</span>, <span class="string">&quot;set2&quot;</span>, <span class="string">&quot;set3&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 随机查询出一个元素，或指定count个元素</span></span><br><span class="line">    List&lt;String&gt; values = jedis.srandmember(<span class="string">&quot;set&quot;</span>, <span class="number">2</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : values) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询集合所有元素</span></span><br><span class="line">    Set&lt;String&gt; all = jedis.smembers(<span class="string">&quot;set&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : all) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询集合共有多少个元素</span></span><br><span class="line">    Long count = jedis.scard(<span class="string">&quot;set&quot;</span>);</span><br><span class="line">    System.out.println(count);</span><br><span class="line">    </span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="4）Hash-类型">
          <a href="#4）Hash-类型" class="heading-link"><i class="fas fa-link"></i></a>4）Hash 类型</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Hash 类型测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test_hash</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line">    jedis.flushDB();</span><br><span class="line">    Map&lt;String, String&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    map.put(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;zhangsan&quot;</span>);</span><br><span class="line">    map.put(<span class="string">&quot;age&quot;</span>, <span class="string">&quot;18&quot;</span>);</span><br><span class="line">    map.put(<span class="string">&quot;sex&quot;</span>, <span class="string">&quot;man&quot;</span>);</span><br><span class="line">    jedis.hset(<span class="string">&quot;user&quot;</span>, map);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果 key 中 field 不存在，添加成功，否则添加失败</span></span><br><span class="line">    jedis.hsetnx(<span class="string">&quot;user&quot;</span>, <span class="string">&quot;city&quot;</span>, <span class="string">&quot;beijing&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 根据 key 的属性查询 value</span></span><br><span class="line">    String name = jedis.hget(<span class="string">&quot;user&quot;</span>, <span class="string">&quot;name&quot;</span>);</span><br><span class="line">    System.out.println(name);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询 key 中是否存在某个 field</span></span><br><span class="line">    Boolean hexists = jedis.hexists(<span class="string">&quot;user&quot;</span>, <span class="string">&quot;address&quot;</span>);</span><br><span class="line">    System.out.println(hexists);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询 key 中所有的 field</span></span><br><span class="line">    Set&lt;String&gt; user = jedis.hkeys(<span class="string">&quot;user&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : user) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询 key 中所有 value</span></span><br><span class="line">    List&lt;String&gt; value = jedis.hvals(<span class="string">&quot;user&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : value) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="5）ZSet-类型">
          <a href="#5）ZSet-类型" class="heading-link"><i class="fas fa-link"></i></a>5）ZSet 类型</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * zset 类型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test_zset</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line">    jedis.flushDB();</span><br><span class="line"></span><br><span class="line">    Map&lt;String, Double&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    map.put(<span class="string">&quot;age&quot;</span>, (<span class="keyword">double</span>)<span class="number">2</span>);</span><br><span class="line">    jedis.zadd(<span class="string">&quot;user&quot;</span>, (<span class="keyword">double</span>) <span class="number">1</span>, <span class="string">&quot;name&quot;</span>);</span><br><span class="line">    jedis.zadd(<span class="string">&quot;user&quot;</span>, map);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 升序排序后查询</span></span><br><span class="line">    Set&lt;String&gt; user = jedis.zrange(<span class="string">&quot;user&quot;</span>, <span class="number">0</span>, -<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : user) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 降序排序后查询</span></span><br><span class="line">    Set&lt;String&gt; user1 = jedis.zrevrange(<span class="string">&quot;user&quot;</span>, <span class="number">0</span>, -<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">for</span> (String str : user1) &#123;</span><br><span class="line">        System.out.println(str);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    jedis.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="3、模拟发送验证码">
          <a href="#3、模拟发送验证码" class="heading-link"><i class="fas fa-link"></i></a>3、模拟发送验证码</h2>
      <p>要求：</p>
<ol>
<li>输入手机号，点击发送后随机生成 6 位数字码，两分钟有效。</li>
<li>输入验证码，点击验证，返回成功或失败。</li>
<li>每个手机号每天只能输入 3 次。</li>
</ol>

        <h3 id="1）创建一个生成验证码的方法">
          <a href="#1）创建一个生成验证码的方法" class="heading-link"><i class="fas fa-link"></i></a>1）创建一个生成验证码的方法</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getCode</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Random random = <span class="keyword">new</span> Random();</span><br><span class="line">    StringBuilder code = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">        code.append(random.nextInt(<span class="number">10</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> code.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="2）创建生成验证码的方法">
          <a href="#2）创建生成验证码的方法" class="heading-link"><i class="fas fa-link"></i></a>2）创建生成验证码的方法</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Boolean <span class="title">createCodeByPhoneNum</span><span class="params">(String phoneNum)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">boolean</span> result = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 验证码发送次数</span></span><br><span class="line">    String sendCountKey = <span class="string">&quot;sendCode&quot;</span> + phoneNum + <span class="string">&quot;:count&quot;</span>;</span><br><span class="line">    <span class="comment">// 验证码 key</span></span><br><span class="line">    String codeKey = <span class="string">&quot;code&quot;</span> + phoneNum + <span class="string">&quot;:code&quot;</span>;</span><br><span class="line">    <span class="comment">// 验证码</span></span><br><span class="line">    String code = getCode();</span><br><span class="line">    <span class="comment">// 是否可以存入验证码</span></span><br><span class="line">    <span class="keyword">boolean</span> saveCode = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 1、获取手机号对应发送的次数</span></span><br><span class="line">    String count = jedis.get(sendCountKey);</span><br><span class="line">    <span class="keyword">if</span> (count == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 没有发送过，设置发送次数为1</span></span><br><span class="line">        jedis.setex(sendCountKey, <span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span>, <span class="string">&quot;1&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (Integer.parseInt(count) &lt; <span class="number">3</span>) &#123;</span><br><span class="line">        <span class="comment">// 发送次数 +1</span></span><br><span class="line">        jedis.incr(sendCountKey);</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (Integer.parseInt(count) &gt; <span class="number">2</span>) &#123;</span><br><span class="line">        <span class="comment">// 已经发送三次了</span></span><br><span class="line">        saveCode = <span class="keyword">false</span>;</span><br><span class="line">        result = <span class="keyword">false</span>;</span><br><span class="line">        <span class="comment">//jedis.close();</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2、保存验证码</span></span><br><span class="line">    <span class="keyword">if</span> (saveCode) &#123;</span><br><span class="line">        jedis.setex(codeKey, <span class="number">60</span> * <span class="number">2</span>, code);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    jedis.close();</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h3 id="3）创建校验验证码的方法">
          <a href="#3）创建校验验证码的方法" class="heading-link"><i class="fas fa-link"></i></a>3）创建校验验证码的方法</h3>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Boolean <span class="title">verifyCodeByPhoneNum</span><span class="params">(String phoneNum, String code)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">&quot;192.168.111.144&quot;</span>, <span class="number">6379</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 验证码 key</span></span><br><span class="line">    String codeKey = <span class="string">&quot;code&quot;</span> + phoneNum + <span class="string">&quot;:code&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 获取验证码</span></span><br><span class="line">    String redisCode = jedis.get(codeKey);</span><br><span class="line"></span><br><span class="line">    jedis.close();</span><br><span class="line">    <span class="keyword">if</span> (redisCode == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (redisCode.equals(code)) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>




        <h1 id="九、SpringBoot-整合-Redis">
          <a href="#九、SpringBoot-整合-Redis" class="heading-link"><i class="fas fa-link"></i></a>九、SpringBoot 整合 Redis</h1>
      
        <h2 id="1、在-pom-文件中引入相关依赖">
          <a href="#1、在-pom-文件中引入相关依赖" class="heading-link"><i class="fas fa-link"></i></a>1、在 pom 文件中引入相关依赖</h2>
      <figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--redis--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jedis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.6.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.5.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.commons<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-pool2<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.8.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="2、application-yml-配置-redis-相关配置">
          <a href="#2、application-yml-配置-redis-相关配置" class="heading-link"><i class="fas fa-link"></i></a>2、application.yml 配置 redis 相关配置</h2>
      <figure class="highlight yaml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line"><span class="comment">#    Redis 服务器地址</span></span><br><span class="line">    <span class="attr">host:</span> <span class="number">192.168</span><span class="number">.111</span><span class="number">.144</span></span><br><span class="line"><span class="comment">#    端口</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">6379</span></span><br><span class="line"><span class="comment">#    数据库索引</span></span><br><span class="line">    <span class="attr">database:</span> <span class="number">0</span></span><br><span class="line"><span class="comment">#    连接超时时间（毫秒）</span></span><br><span class="line"><span class="comment">#    timeout: 1800000</span></span><br><span class="line">    <span class="attr">jedis:</span></span><br><span class="line">      <span class="attr">pool:</span></span><br><span class="line"><span class="comment">#        连接池最大连接数（负数表示没有限制）</span></span><br><span class="line">        <span class="attr">max-active:</span></span><br><span class="line"><span class="comment">#        最大阻塞等待时间（负数表示没有限制）</span></span><br><span class="line">        <span class="attr">max-wait:</span> <span class="number">-1</span></span><br><span class="line"><span class="comment">#        连接池中最大空闲连接</span></span><br><span class="line">        <span class="attr">max-idle:</span> <span class="number">5</span></span><br><span class="line"><span class="comment">#        连接池值最小空闲连接</span></span><br><span class="line">        <span class="attr">min-idle:</span> <span class="number">0</span></span><br></pre></td></tr></table></div></figure>


        <h2 id="3、配置-redis-配置类">
          <a href="#3、配置-redis-配置类" class="heading-link"><i class="fas fa-link"></i></a>3、配置 redis 配置类</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableCaching</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisConfig</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RedisTemplate&lt;String, Object&gt; <span class="title">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> <span class="keyword">throws</span> UnknownHostException </span>&#123;</span><br><span class="line">        <span class="comment">// 我们为了自己开发方便，一般直接使用 &lt;String, Object&gt;</span></span><br><span class="line">        <span class="comment">// 两个泛型都是 Object, Object 的类型，我们后使用需要强制转换 &lt;String, Object&gt;</span></span><br><span class="line">        RedisTemplate&lt;String, Object&gt; template = <span class="keyword">new</span> RedisTemplate&lt;&gt;();</span><br><span class="line">        template.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        setRedisTemplate(template);</span><br><span class="line">        template.afterPropertiesSet();</span><br><span class="line">        <span class="keyword">return</span> template;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">setRedisTemplate</span><span class="params">(RedisTemplate&lt;String, Object&gt; template)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// Json序列化配置</span></span><br><span class="line">        Jackson2JsonRedisSerializer&lt;Object&gt; jackson2JsonRedisSerializer = <span class="keyword">new</span> Jackson2JsonRedisSerializer&lt;&gt;(Object.class);</span><br><span class="line"></span><br><span class="line">        ObjectMapper objectMapper = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line">        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);</span><br><span class="line">        <span class="comment">// 解决jackson2无法反序列化LocalDateTime的问题</span></span><br><span class="line">        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);</span><br><span class="line">        objectMapper.registerModule(<span class="keyword">new</span> JavaTimeModule());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 该方法过时</span></span><br><span class="line">        <span class="comment">// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span></span><br><span class="line">        <span class="comment">// 上面 enableDefaultTyping 方法过时，使用 activateDefaultTyping</span></span><br><span class="line">        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);</span><br><span class="line">        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// String 的序列化</span></span><br><span class="line">        StringRedisSerializer stringRedisSerializer = <span class="keyword">new</span> StringRedisSerializer();</span><br><span class="line">        <span class="comment">// key采用String的序列化方式</span></span><br><span class="line">        template.setKeySerializer(stringRedisSerializer);</span><br><span class="line">        <span class="comment">// hash的key也采用String的序列化方式</span></span><br><span class="line">        template.setHashKeySerializer(stringRedisSerializer);</span><br><span class="line">        <span class="comment">// value序列化方式采用jackson</span></span><br><span class="line">        template.setValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line">        <span class="comment">// hash的value序列化方式采用jackson</span></span><br><span class="line">        template.setHashValueSerializer(jackson2JsonRedisSerializer);</span><br><span class="line">        <span class="comment">// 设置值（value）的序列化采用FastJsonRedisSerializer。</span></span><br><span class="line">        <span class="comment">// 设置键（key）的序列化采用StringRedisSerializer。</span></span><br><span class="line">        template.afterPropertiesSet();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>


        <h2 id="4、redis-工具类">
          <a href="#4、redis-工具类" class="heading-link"><i class="fas fa-link"></i></a>4、redis 工具类</h2>
      <p>使用的时候注入即可</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.sy.jedis_redisdemo.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.CollectionUtils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Collection;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> RedisUtil</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> sy</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2021/8/15 22:20</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RedisUtil</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> RedisTemplate&lt;String, Object&gt; redisTemplate;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// =============================common============================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * sy</span></span><br><span class="line"><span class="comment">     * 监视 key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">watch</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (key != <span class="keyword">null</span> &amp;&amp; key != <span class="string">&quot;&quot;</span>) &#123;</span><br><span class="line">                redisTemplate.watch(key);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * sy</span></span><br><span class="line"><span class="comment">     * 监视 key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> keys  键</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">watch</span><span class="params">(Collection&lt;String&gt; keys)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (keys != <span class="keyword">null</span> &amp;&amp; keys.size()&gt;<span class="number">0</span>) &#123;</span><br><span class="line">                redisTemplate.watch(keys);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * sy</span></span><br><span class="line"><span class="comment">     * 解除监视 key</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">unwatch</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.unwatch();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 指定缓存失效时间</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time 时间(秒)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">expire</span><span class="params">(String key, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                redisTemplate.expire(key, time, TimeUnit.SECONDS);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据key 获取过期时间</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键 不能为null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 时间(秒) 返回0代表为永久有效</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">getExpire</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.getExpire(key, TimeUnit.SECONDS);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 判断key是否存在</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 存在 false不存在</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasKey</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.hasKey(key);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 删除缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 可以传一个值 或多个</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">del</span><span class="params">(String... key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (key != <span class="keyword">null</span> &amp;&amp; key.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (key.length == <span class="number">1</span>) &#123;</span><br><span class="line">                redisTemplate.delete(key[<span class="number">0</span>]);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                redisTemplate.delete((Collection&lt;String&gt;) CollectionUtils.arrayToList(key));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ============================String=============================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 普通缓存获取</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">get</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> key == <span class="keyword">null</span> ? <span class="keyword">null</span> : redisTemplate.opsForValue().get(key);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 普通缓存放入</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true成功 false失败</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">set</span><span class="params">(String key, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForValue().set(key, value);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 普通缓存放入并设置时间</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time  时间(秒) time要大于0 如果time小于等于0 将设置无限期</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true成功 false 失败</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">set</span><span class="params">(String key, Object value, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                set(key, value);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 递增</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> delta 要增加几(大于0)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">incr</span><span class="params">(String key, <span class="keyword">long</span> delta)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (delta &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;递增因子必须大于0&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForValue().increment(key, delta);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 递减</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> delta 要减少几(小于0)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">decr</span><span class="params">(String key, <span class="keyword">long</span> delta)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (delta &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;递减因子必须大于0&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForValue().increment(key, -delta);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ================================Map=================================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * HashGet</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键 不能为null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item 项 不能为null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">hget</span><span class="params">(String key, String item)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForHash().get(key, item);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取hashKey对应的所有键值</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 对应的多个键值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;Object, Object&gt; <span class="title">hmget</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForHash().entries(key);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * HashSet</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> map 对应多个键值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hmset</span><span class="params">(String key, Map&lt;String, Object&gt; map)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForHash().putAll(key, map);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * HashSet 并设置时间</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> map  对应多个键值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time 时间(秒)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true成功 false失败</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hmset</span><span class="params">(String key, Map&lt;String, Object&gt; map, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForHash().putAll(key, map);</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                expire(key, time);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 向一张hash表中放入数据,如果不存在将创建</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item  项</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 成功 false失败</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hset</span><span class="params">(String key, String item, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForHash().put(key, item, value);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 向一张hash表中放入数据,如果不存在将创建</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item  项</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 成功 false失败</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hset</span><span class="params">(String key, String item, Object value, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForHash().put(key, item, value);</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                expire(key, time);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 删除hash表中的值</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键 不能为null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item 项 可以使多个 不能为null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">hdel</span><span class="params">(String key, Object... item)</span> </span>&#123;</span><br><span class="line">        redisTemplate.opsForHash().delete(key, item);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 判断hash表中是否有该项的值</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键 不能为null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item 项 不能为null</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 存在 false不存在</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hHasKey</span><span class="params">(String key, String item)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForHash().hasKey(key, item);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * hash递增 如果不存在,就会创建一个 并把新增后的值返回</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item 项</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> by   要增加几(大于0)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">hincr</span><span class="params">(String key, String item, <span class="keyword">double</span> by)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForHash().increment(key, item, by);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * hash递减</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key  键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> item 项</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> by   要减少记(小于0)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">hdecr</span><span class="params">(String key, String item, <span class="keyword">double</span> by)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> redisTemplate.opsForHash().increment(key, item, -by);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ============================set=============================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据key获取Set中的所有值</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Set&lt;Object&gt; <span class="title">sGet</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForSet().members(key);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据value从一个set中查询,是否存在</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> true 存在 false不存在</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">sHasKey</span><span class="params">(String key, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForSet().isMember(key, value);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将数据放入set缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> values 值 可以是多个</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功个数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">sSet</span><span class="params">(String key, Object... values)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForSet().add(key, values);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将set数据放入缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time   时间(秒)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> values 值 可以是多个</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功个数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">sSetAndTime</span><span class="params">(String key, <span class="keyword">long</span> time, Object... values)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Long count = redisTemplate.opsForSet().add(key, values);</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                expire(key, time);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> count;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取set缓存的长度</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">sGetSetSize</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForSet().size(key);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 移除值为value的</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> values 值 可以是多个</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 移除的个数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">setRemove</span><span class="params">(String key, Object... values)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Long count = redisTemplate.opsForSet().remove(key, values);</span><br><span class="line">            <span class="keyword">return</span> count;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ===============================list=================================</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取list缓存的内容</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> start 开始</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> end   结束 0 到 -1代表所有值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;Object&gt; <span class="title">lGet</span><span class="params">(String key, <span class="keyword">long</span> start, <span class="keyword">long</span> end)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForList().range(key, start, end);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取list缓存的长度</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 键</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">lGetListSize</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForList().size(key);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过索引 获取list中的值</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index 索引 index&gt;=0时， 0 表头，1 第二个元素，依次类推；index&lt;0时，-1，表尾，-2倒数第二个元素，依次类推</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">lGetIndex</span><span class="params">(String key, <span class="keyword">long</span> index)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> redisTemplate.opsForList().index(key, index);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将list放入缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">lSet</span><span class="params">(String key, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForList().rightPush(key, value);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将list放入缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time  时间(秒)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">lSet</span><span class="params">(String key, Object value, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForList().rightPush(key, value);</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                expire(key, time);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将list放入缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">lSet</span><span class="params">(String key, List&lt;Object&gt; value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForList().rightPushAll(key, value);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将list放入缓存</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> time  时间(秒)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">lSet</span><span class="params">(String key, List&lt;Object&gt; value, <span class="keyword">long</span> time)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForList().rightPushAll(key, value);</span><br><span class="line">            <span class="keyword">if</span> (time &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                expire(key, time);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据索引修改list中的某条数据</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index 索引</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">lUpdateIndex</span><span class="params">(String key, <span class="keyword">long</span> index, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            redisTemplate.opsForList().set(key, index, value);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 移除N个值为value</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key   键</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> count 移除多少个</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 移除的个数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">lRemove</span><span class="params">(String key, <span class="keyword">long</span> count, Object value)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Long remove = redisTemplate.opsForList().remove(key, count, value);</span><br><span class="line">            <span class="keyword">return</span> remove;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>


        <h2 id="5、编写-controller-测试">
          <a href="#5、编写-controller-测试" class="heading-link"><i class="fas fa-link"></i></a>5、编写 controller 测试</h2>
      <figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> RedisUtil redisUtil;</span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * sy</span></span><br><span class="line"><span class="comment">    * 验证redis整合</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> ResultBody</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="meta">@ApiOperation(value = &quot;验证redis整合&quot;)</span></span><br><span class="line">   <span class="meta">@GetMapping(value = &quot;/verifyRedis&quot;)</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> ResultBody <span class="title">verifyRedis</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">       redisUtil.set(<span class="string">&quot;test&quot;</span>, <span class="string">&quot;ceshi&quot;</span>);</span><br><span class="line">       String value = (String) redisUtil.get(<span class="string">&quot;test&quot;</span>);</span><br><span class="line"></span><br><span class="line">       System.out.println(value);</span><br><span class="line"></span><br><span class="line">       <span class="keyword">return</span> ResultBody.success();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></div></figure>


        <h1 id="十、Redis-事务和锁机制">
          <a href="#十、Redis-事务和锁机制" class="heading-link"><i class="fas fa-link"></i></a>十、Redis 事务和锁机制</h1>
      <p><strong>Redis</strong> 事务是一个单独的隔离操作：事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中，不会被其他客户端发送来的命令请求所打断。</p>
<p><strong>Redis</strong> 事务的主要作用就是<font color="red">串联多个命令防止别的命令插队。</font></p>

        <h2 id="1、基本操作">
          <a href="#1、基本操作" class="heading-link"><i class="fas fa-link"></i></a>1、基本操作</h2>
      
        <h3 id="1）、Multi、Exec、Discard">
          <a href="#1）、Multi、Exec、Discard" class="heading-link"><i class="fas fa-link"></i></a>1）、Multi、Exec、Discard</h3>
      <p><strong>Multi：</strong>开始事务，进行组队阶段</p>
<p><strong>Exec：</strong>执行阶段，按照顺序执行</p>
<p><strong>Discard：</strong>放弃执行</p>
<p>从输入 <strong>Multi</strong> 命令开始，输入的命令都会依次进入命令队列中，但不会执行，直到输入 <strong>Exec</strong> 后，<strong>Redis</strong> 都会将之前的命令队列中的命令依次执行。</p>
<p>组队的过程中可以通过 <strong>Discard</strong> 来放弃组队</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/29.png" alt="图片加载失败"></p>
<p><strong>示例：</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 开启事务</span></span><br><span class="line">multi</span><br><span class="line">set key1 value1</span><br><span class="line">set key2 value2</span><br><span class="line"><span class="meta">#</span><span class="bash"> 执行</span></span><br><span class="line">exec</span><br><span class="line">keys *</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 开启事务</span></span><br><span class="line">multi</span><br><span class="line">set a1 v1</span><br><span class="line">set a2 v2</span><br><span class="line"><span class="meta">#</span><span class="bash"> 放弃事务</span></span><br><span class="line">discard</span><br><span class="line">keys *</span><br></pre></td></tr></table></div></figure>


        <h3 id="2）事务的错误处理">
          <a href="#2）事务的错误处理" class="heading-link"><i class="fas fa-link"></i></a>2）事务的错误处理</h3>
      <p>事务可能会出现的错误有两种：</p>
<ol>
<li><p>组队中某个命令出现了报告错误，执行时整个的所有队列都会被取消</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/30.png" alt="图片加载失败"></p>
<p><strong>示例：</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/31.png" alt="图片加载失败"></p>
</li>
</ol>
<ol start="2">
<li><p>执行阶段某个命令出现了错误，则只有报错的命令不会执行，而其他命令正常执行。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/32.png" alt="图片加载失败"></p>
</li>
</ol>

        <h2 id="2、事务冲突的问题">
          <a href="#2、事务冲突的问题" class="heading-link"><i class="fas fa-link"></i></a>2、事务冲突的问题</h2>
      <p><strong>场景：</strong>有很多人有你的账户，同事去参加双十一抢购</p>

        <h2 id="3、例子">
          <a href="#3、例子" class="heading-link"><i class="fas fa-link"></i></a>3、例子</h2>
      <ul>
<li>一个请求想给金额减8000</li>
<li>一个请求想给金额减5000</li>
<li>一个请求想给金额减1000</li>
</ul>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/33.png" alt="图片加载失败"></p>

        <h3 id="1）解决方案">
          <a href="#1）解决方案" class="heading-link"><i class="fas fa-link"></i></a>1）解决方案</h3>
      
        <h4 id="1-悲观锁">
          <a href="#1-悲观锁" class="heading-link"><i class="fas fa-link"></i></a>1. 悲观锁</h4>
      <p><strong>什么是悲观锁：</strong>顾名思义，就是很悲观，每次去拿数据的时候都认为别人会修改，所以每次在拿到数据的时候都会上锁，这样别人想去拿这个数据就会 <strong>block（阻塞）</strong>,知道他用完数据，将锁释放后，被人才可以拿到数据。<font color="red">传统的关系型数据库中就用到了很多这种锁机制</font>，比如<font color="red">行锁</font>，<font color="red">表锁</font>等，<font color="red">读锁</font>，<font color="red">写锁</font>等，都是在做操作之前先上锁<font color="red">锁</font>。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/34.png" alt="图片加载失败"></p>

        <h4 id="2-乐观锁">
          <a href="#2-乐观锁" class="heading-link"><i class="fas fa-link"></i></a>2.乐观锁</h4>
      <p><strong>什么是乐观锁：</strong>顾名思义，就是很乐观，每次去拿数据的时候都认为别人不会修改，所以不会上锁，但是在更新的时候会判断一下在此期间别人有没有去更新这个数据，可以使用版本号等机制。<font color="red">乐观锁适用于多读的应用类型，这样可以提高吞吐量。Redis 就是利用这种 check-and-set 机制实现事务的</font>。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/35.png" alt="图片加载失败"></p>

        <h4 id="3-watch-key-key…-命令">
          <a href="#3-watch-key-key…-命令" class="heading-link"><i class="fas fa-link"></i></a>3.watch key [key…] 命令</h4>
      <p>在执行 <strong>Multi</strong> 之前，先执行 <strong>watch key [keys…]</strong> 命令，可以监视一个（或多个）<strong>key</strong>，如果在事务执行之前这个（这些）<strong>key</strong> 被其他命令所改动，那么事务将会被打断</p>
<p><strong>测试例子：</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/41.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/42.png" alt="图片加载失败"></p>

        <h2 id="4、Redis-事务三特性">
          <a href="#4、Redis-事务三特性" class="heading-link"><i class="fas fa-link"></i></a>4、Redis 事务三特性</h2>
      <ol>
<li><p>单独的隔离操作：</p>
<p>事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中，不会被其他客户端发送的命令请求打断。</p>
</li>
<li><p>没有隔离级别的概念：</p>
<p>队列中的命令没有提交之前都不会实际被执行，因为事务提交前任何指令都不会被实际执行。</p>
</li>
<li><p>不保证原子性：</p>
<p>事务中如果有一条命令执行失败，其后的命令仍然会被执行，没有回滚。</p>
</li>
</ol>

        <h2 id="5、秒杀案例">
          <a href="#5、秒杀案例" class="heading-link"><i class="fas fa-link"></i></a>5、秒杀案例</h2>
      
        <h3 id="1）基本实现">
          <a href="#1）基本实现" class="heading-link"><i class="fas fa-link"></i></a>1）基本实现</h3>
      <p><strong>页面：</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/36.png" alt="图片加载失败"></p>
<figure class="highlight html"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="meta-keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span> <span class="attr">xmlns:th</span>=<span class="string">&quot;http://www.thymeleaf.org&quot;</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--&lt;script th:src=&quot;@&#123;/webjars/jquery/3.5.1/jquery.min.js&#125;&quot;&gt;&lt;/script&gt;--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;webjars/jquery/3.5.1/jquery.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>iPhone 13 pro!!! 1元秒杀！！！<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">&quot;msform&quot;</span> <span class="attr">action</span>=<span class="string">&quot;http://localhost:8079/redis/ms/doseckill&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;hidden&quot;</span> <span class="attr">id</span>=<span class="string">&quot;prodid&quot;</span> <span class="attr">name</span>=<span class="string">&quot;prodid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;0101&quot;</span>&gt;</span></span><br><span class="line">    用户id：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;userId&quot;</span> <span class="attr">name</span>=<span class="string">&quot;userid&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;button&quot;</span> <span class="attr">id</span>=<span class="string">&quot;miaosha_btn&quot;</span> <span class="attr">name</span>=<span class="string">&quot;seckill_btn&quot;</span> <span class="attr">value</span>=<span class="string">&quot;秒杀点我&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="javascript">    $(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> form = $(<span class="string">&quot;#msform&quot;</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> parems = &#123;&#125;;</span></span><br><span class="line"></span><br><span class="line"><span class="javascript">        $(<span class="string">&quot;#miaosha_btn&quot;</span>).click(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            parems.userId = $(<span class="string">&quot;#userId&quot;</span>).val();</span></span><br><span class="line"><span class="javascript">            parems.prodid = $(<span class="string">&quot;#prodid&quot;</span>).val();</span></span><br><span class="line"><span class="javascript">            $.ajax(&#123;</span></span><br><span class="line"><span class="javascript">                type: <span class="string">&quot;post&quot;</span>,</span></span><br><span class="line"><span class="javascript">                url: <span class="string">&quot;http://localhost:8079/redis/ms/doseckill&quot;</span>,</span></span><br><span class="line"><span class="javascript">                data: <span class="built_in">JSON</span>.stringify(parems),</span></span><br><span class="line"><span class="javascript">                dataType: <span class="string">&quot;json&quot;</span>,</span></span><br><span class="line"><span class="javascript">                contentType: <span class="string">&quot;application/json;charset=utf-8&quot;</span>,</span></span><br><span class="line"><span class="javascript">                success: <span class="function"><span class="keyword">function</span> (<span class="params">data</span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">                    <span class="comment">// if (data === &quot;false&quot;) &#123;</span></span></span><br><span class="line"><span class="javascript">                    <span class="comment">//     alert(&quot;抢光了&quot;);</span></span></span><br><span class="line"><span class="javascript">                    <span class="comment">//     $(&quot;#miaosha_btn&quot;).attr(&quot;disabled&quot;, true);</span></span></span><br><span class="line"><span class="javascript">                    <span class="comment">// &#125;</span></span></span><br><span class="line"><span class="javascript">                    <span class="keyword">if</span> (data.code === <span class="string">&quot;00000&quot;</span>) &#123;</span></span><br><span class="line">                        alert(data.message);</span><br><span class="line"><span class="javascript">                        $(<span class="string">&quot;#miaosha_btn&quot;</span>).attr(<span class="string">&quot;disabled&quot;</span>, <span class="literal">true</span>);</span></span><br><span class="line"><span class="javascript">                    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (data.code === <span class="string">&quot;50000&quot;</span>) &#123;</span></span><br><span class="line">                        alert(data.message);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line"></span><br><span class="line">    &#125;)</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></div></figure>

<p><strong>实体类：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.sy.jedis_redisdemo.restful.beans;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> User</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> sy</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2021/8/16 19:39</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String userId;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String prodid;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>

<p><strong>Controller：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.sy.jedis_redisdemo.restful.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sy.api.context.ResultBody;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.restful.beans.User;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.restful.service.MsService;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.Api;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiOperation;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> MsController</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> sy</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2021/8/16 18:14</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Api(value = &quot;秒杀&quot;, tags = &quot;秒杀&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/ms&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MsController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> MsService msService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;秒杀&quot;)</span></span><br><span class="line">    <span class="meta">@PostMapping(value = &quot;/doseckill&quot;)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ResultBody <span class="title">doseckill</span><span class="params">(<span class="meta">@RequestBody</span> User user)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> msService.doseckill(user);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>Service：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.sy.jedis_redisdemo.restful.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sy.api.context.ResultBody;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.restful.beans.User;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> MsService</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> sy</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2021/8/16 19:43</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MsService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function">ResultBody <span class="title">doseckill</span><span class="params">(User user)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></div></figure>

<p><strong>ServiceImpl：</strong></p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.sy.jedis_redisdemo.restful.service.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.api.R;</span><br><span class="line"><span class="keyword">import</span> com.sy.api.context.ResultBody;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.restful.beans.User;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.restful.service.MsService;</span><br><span class="line"><span class="keyword">import</span> com.sy.jedis_redisdemo.utils.RedisUtil;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.lang3.StringUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"><span class="keyword">import</span> sun.net.RegisteredDomain;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ClassName</span> MsServiceImpl</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> TODO</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span> sy</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span> 2021/8/16 19:43</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MsServiceImpl</span> <span class="keyword">implements</span> <span class="title">MsService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> RedisUtil redisUtil;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ResultBody <span class="title">doseckill</span><span class="params">(User user)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//1、userId 和 prodid 非空判断</span></span><br><span class="line">        <span class="keyword">if</span> (StringUtils.isEmpty(user.userId) || StringUtils.isEmpty(user.prodid)) &#123;</span><br><span class="line">            <span class="keyword">return</span> ResultBody.error(<span class="string">&quot;用户或商品id不能为空&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//2、连接 redis</span></span><br><span class="line">        <span class="comment">//Jedis jedis = new Jedis(&quot;192.168.111.144&quot;, 6379);</span></span><br><span class="line">        <span class="comment">//RedisUtil redisUtil = new RedisUtil();</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//3、拼接key</span></span><br><span class="line">        <span class="comment">//3.1 库存key</span></span><br><span class="line">        String kcKey = <span class="string">&quot;sk:&quot;</span> + user.prodid + <span class="string">&quot;:kc&quot;</span>;</span><br><span class="line">        <span class="comment">//3.2 秒杀成功用户key</span></span><br><span class="line">        String userKey = <span class="string">&quot;sk:&quot;</span> + user.prodid + <span class="string">&quot;:user&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//4、获取库存，如果库存为null，秒杀还未开始</span></span><br><span class="line">        Object kc = redisUtil.get(kcKey);</span><br><span class="line">        <span class="keyword">if</span> (kc == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> ResultBody.error(<span class="string">&quot;秒杀未开始，请等待！&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//5、判断用户是否重复秒杀操作</span></span><br><span class="line">        <span class="keyword">if</span> (redisUtil.sHasKey(userKey, user.userId)) &#123;</span><br><span class="line">            <span class="keyword">return</span> ResultBody.error(<span class="string">&quot;已经秒杀成功，不能重复秒杀！&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//6、判断库存数量，如果数量小于1，秒杀结束</span></span><br><span class="line">        <span class="keyword">if</span> ((<span class="keyword">int</span>)kc &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> ResultBody.error(<span class="string">&quot;秒杀已经结束！&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//7、秒杀过程</span></span><br><span class="line">        <span class="comment">//7.1 库存 -1</span></span><br><span class="line">        redisUtil.decr(kcKey, <span class="number">1</span>);</span><br><span class="line">        <span class="comment">//7.1 把秒杀成功用户添加到清单中</span></span><br><span class="line">        redisUtil.sSet(userKey, user.userId);</span><br><span class="line">        <span class="keyword">return</span> ResultBody.success(<span class="string">&quot;秒杀成功！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></div></figure>


        <h3 id="2）ab工具模拟并发">
          <a href="#2）ab工具模拟并发" class="heading-link"><i class="fas fa-link"></i></a>2）ab工具模拟并发</h3>
      
        <h4 id="2-1）安装-httpd-tools">
          <a href="#2-1）安装-httpd-tools" class="heading-link"><i class="fas fa-link"></i></a>2-1）安装 httpd-tools</h4>
      <p>执行 <strong>yum install httpd-tools</strong> 安装</p>

        <h4 id="2-2）命令及常用参数">
          <a href="#2-2）命令及常用参数" class="heading-link"><i class="fas fa-link"></i></a>2-2）命令及常用参数</h4>
      <p><strong>常用参数：</strong>ab –list 可查看所有参数</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 请求次数</span></span><br><span class="line">   -n requests     Number of requests to perform</span><br><span class="line"><span class="meta">   #</span><span class="bash"> 并发次数</span></span><br><span class="line">   -c concurrency  Number of multiple requests to make at a time</span><br><span class="line"><span class="meta">   #</span><span class="bash"> 提交参数,参数要写到文件中，针对post,使用时要设置 -T</span></span><br><span class="line">   -p postfile     File containing data to POST. Remember also to set -T</span><br><span class="line">   -u putfile      File containing data to PUT. Remember also to set -T</span><br><span class="line"><span class="meta">   #</span><span class="bash"> 设置 content-type，和你请求的 content-type 一样</span></span><br><span class="line">   -T content-type Content-type header to use for POST/PUT data, eg.</span><br><span class="line">                   &#x27;application/x-www-form-urlencoded&#x27;</span><br><span class="line">                   Default is &#x27;text/plain&#x27;  </span><br></pre></td></tr></table></div></figure>

<p><strong>命令：</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 1000 次请求，其中并发请求有100个，参数文件是 postfiel</span></span><br><span class="line">ab -n 1000 -c 100 -p postfile -T &#x27;application/json;charset=utf-8&#x27; http://192.168.111.2:8079/redis/ms/doseckill</span><br></pre></td></tr></table></div></figure>


        <h4 id="2-3）测试">
          <a href="#2-3）测试" class="heading-link"><i class="fas fa-link"></i></a>2-3）测试</h4>
      <ol>
<li><p><strong>创建 postfile 参数文件内容（用于 ab 工具测试并发发送的参数）：</strong></p>
<figure class="highlight json"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;<span class="attr">&quot;prodid&quot;</span> : <span class="string">&quot;0101&quot;</span>&#125;</span><br></pre></td></tr></table></div></figure>
</li>
<li><p><strong>修改 controller：</strong>因为同一个 <strong>userId</strong> 不能重复秒杀，所以我们在这里随机一个。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/37.png" alt="图片加载失败"></p>
</li>
<li><p><strong>执行命令进行测试：</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ab -n 1000 -c 100 -p postfile -T &#x27;application/json;charset=utf-8&#x27; http://192.168.111.2:8079/redis/ms/doseckill</span><br></pre></td></tr></table></div></figure>
</li>
<li><p><strong>查看执行结果：</strong></p>
<p>执行命令的结果：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/38.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/39.png" alt="图片加载失败"></p>
<p><strong>redis</strong> 中数据情况：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/40.png" alt="图片加载失败"></p>
</li>
<li><p>出现的问题：</p>
<ul>
<li>在上面测试结果中可以看到库存数量变为了 -35 ，这里出现的就是 <strong>超卖</strong> 的问题</li>
<li>还可能会出现 <strong>连接超时的问题</strong></li>
</ul>
</li>
</ol>

        <h3 id="3）超卖和连接超时问题解决">
          <a href="#3）超卖和连接超时问题解决" class="heading-link"><i class="fas fa-link"></i></a>3）超卖和连接超时问题解决</h3>
      
        <h4 id="3-1）连接超时问题">
          <a href="#3-1）连接超时问题" class="heading-link"><i class="fas fa-link"></i></a>3-1）连接超时问题</h4>
      <p>这个问题在 <strong><span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://sunyubk.github.io/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/#%E4%B9%9D%E3%80%81SpringBoot-%E6%95%B4%E5%90%88-Redis">SpringBoot 整合 Redis</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></strong> 中，通过 <strong>yml，redisConfig，RedisUtils</strong> 已经解决了</p>

        <h4 id="3-2）超卖问题">
          <a href="#3-2）超卖问题" class="heading-link"><i class="fas fa-link"></i></a>3-2）超卖问题</h4>
      
        <h5 id="1-setnx-解决">
          <a href="#1-setnx-解决" class="heading-link"><i class="fas fa-link"></i></a>1.setnx 解决</h5>
      <p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/44.png" alt="图片加载失败"></p>

        <h5 id="2-Redisson-解决">
          <a href="#2-Redisson-解决" class="heading-link"><i class="fas fa-link"></i></a>2.Redisson 解决</h5>
      <ol>
<li><p>添加依赖</p>
<figure class="highlight xml"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--redisson--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.redisson<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>redisson-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.13.6<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></div></figure>
</li>
<li><p>修改 <strong>serviceImpl</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/45.png" alt="图片加载失败"></p>
<p>这里不用考虑 锁误删的问题，因为Redisson内部已经拼接了，见下图：</p>
<p>这里的 <strong>id</strong> 是 <strong>ConnectionManager</strong> 的一个属性，继续追源码你会发现他也是一个 <strong>UUID</strong> 类型的。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/91.png" alt="图片加载失败"></p>
</li>
</ol>

        <h1 id="十一、Redis-持久化">
          <a href="#十一、Redis-持久化" class="heading-link"><i class="fas fa-link"></i></a>十一、Redis 持久化</h1>
      
        <h2 id="1、RDB">
          <a href="#1、RDB" class="heading-link"><i class="fas fa-link"></i></a>1、RDB</h2>
      
        <h3 id="1）什么是-RDB">
          <a href="#1）什么是-RDB" class="heading-link"><i class="fas fa-link"></i></a>1）什么是 RDB</h3>
      <p><strong>RDB</strong> 就是在指定的<font color="red">时间间隔</font>内将内存中的数据集<font color="red">快照</font>写入磁盘。</p>
<p>直白的说就是：在某一时刻记录下数据快照，在时间间隔内将数据存储到磁盘，恢复的时候也是将快照文件直接读到内存中</p>

        <h3 id="2）备份是如何执行的">
          <a href="#2）备份是如何执行的" class="heading-link"><i class="fas fa-link"></i></a>2）备份是如何执行的</h3>
      <p><strong>Redis</strong> 会单独创建一个 <strong>(Fork)</strong> 一个子进程来进行持久化，会先将数据写入到一个临时文件中，等持久化过程都结束了，再用这个<font color="red">临时文件替换上次持久化好的文件</font>。整个过程中，主进程不进行任何 <strong>IO</strong> 操作，这就确保了极高的性能。如果需要大规模的数据恢复，而且对于数据恢复的完整性不是非常敏感，那 <strong>RDB</strong> 方式要比 <strong>AOF</strong> 方式更加高效。</p>
<p><strong>RDB</strong> 的缺点就是：最后一次持久化后的数据可能丢失。</p>

        <h3 id="3）备份文件位置与备份规则">
          <a href="#3）备份文件位置与备份规则" class="heading-link"><i class="fas fa-link"></i></a>3）备份文件位置与备份规则</h3>
      <p>位置：默认在那个目录下启动 <strong>redis</strong> 服务，文件就生成在哪里。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/46.png" alt="图片加载失败"></p>
<p>规则：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/47.png" alt="图片加载失败"></p>

        <h3 id="4）命令-save-VS-bgsave">
          <a href="#4）命令-save-VS-bgsave" class="heading-link"><i class="fas fa-link"></i></a>4）命令 save VS bgsave</h3>
      <p><strong>Redis</strong> 默认情况下是自动进行备份的。也可以使用下面两个命令进行手动备份。</p>
<p><strong>save：</strong>save 时只管保存，其他不管，全部阻塞。不建议</p>
<p><font color="red"><strong>bgsave：</strong> Redis 会在后台异步进行快照操作，快照同时还可以响应客户端请求。</font></p>

        <h2 id="2、AOF">
          <a href="#2、AOF" class="heading-link"><i class="fas fa-link"></i></a>2、AOF</h2>
      
        <h3 id="1）什么是-AOF">
          <a href="#1）什么是-AOF" class="heading-link"><i class="fas fa-link"></i></a>1）什么是 AOF</h3>
      <p><font color="red">以 <strong>日志</strong> 的形式类记录每个写操作（增量保存）</font>，将 <strong>Redis</strong> 执行过的所有写指令记录下来（<font color="red">读操作不记录</font>），<font color="red">只许追加文件但不可以改写文件</font>，<strong>Redis</strong> 启动之初会读取该文件重新构建数据。简单的来说就是根据日志文件的内容将所有指令从前到后执行一次来完成数据的恢复工作。</p>

        <h3 id="2）AOF-持久化流程">
          <a href="#2）AOF-持久化流程" class="heading-link"><i class="fas fa-link"></i></a>2）AOF 持久化流程</h3>
      <ol>
<li>客户端的请求写命令会被 <strong>append</strong> 追加到 <strong>AOF</strong> 缓冲区内；</li>
<li><strong>AOF</strong> 缓冲区根据 <strong>AOF</strong> 持久化策略 <strong>[always，everysec，no]**，将操作 **sync</strong> 同步到磁盘的 <strong>AOF</strong> 文件中；</li>
<li><strong>AOF</strong> 文件大小超过重写策略或手动重写时，会对 <strong>AOF</strong> 文件 <strong>rewrite</strong> 重写，压缩 <strong>AOF</strong> 文件的容量；</li>
<li><strong>Redis</strong> 服务重启是，会重新 <strong>load</strong> 加载 <strong>AOF</strong> 文件中的写操作达到数据恢复的目的；</li>
</ol>

        <h3 id="3）AOF-默认不开启">
          <a href="#3）AOF-默认不开启" class="heading-link"><i class="fas fa-link"></i></a>3）AOF 默认不开启</h3>
      <p>可以再 <strong>redis.conf</strong> 中配置文件名称，默认为：<strong>appendonly.aof</strong></p>
<p><strong>AOF</strong> 文件的保存路径与 <strong>RDB</strong> 的路径一致</p>

        <h3 id="4）AOF-和-RDB-同时开启，Redis-听谁的？">
          <a href="#4）AOF-和-RDB-同时开启，Redis-听谁的？" class="heading-link"><i class="fas fa-link"></i></a>4）AOF 和 RDB 同时开启，Redis 听谁的？</h3>
      <p><strong>AOF</strong> 和 <strong>RDB</strong> 同时开启，系统默认取 <strong>AOF</strong> 的数据（数据不会存在丢失情况）</p>

        <h3 id="5）AOF-文件损坏xiuf">
          <a href="#5）AOF-文件损坏xiuf" class="heading-link"><i class="fas fa-link"></i></a>5）AOF 文件损坏xiuf</h3>
      <ul>
<li>如果遇到 <strong>AOF</strong> 文件损坏，可以通过：/bin/<font color="red">redis-check-for-aof–fix appendonly.aof</font> 进行恢复</li>
<li>备份被写坏的 <strong>AOF</strong> 文件</li>
<li>恢复：重启 <strong>Redis</strong>，然后会自动加载 <strong>AOF</strong> 文件</li>
</ul>

        <h3 id="6）AOF-同步频率设置">
          <a href="#6）AOF-同步频率设置" class="heading-link"><i class="fas fa-link"></i></a>6）AOF 同步频率设置</h3>
      <ol>
<li><p><strong>appendfsync always</strong></p>
<p>始终同步，每次 <strong>Redis</strong> 的写操作都会like记入日志；性能比较差，但是数据的完整性比较好。</p>
</li>
<li><p><strong>appendfsync everysec</strong></p>
<p>每秒同步，每秒记入日志一次，如果宕机，本秒的数据可能会丢失</p>
</li>
<li><p><strong>appendfsync no</strong></p>
<p><strong>Redis</strong> 不主动进行同步，把同步时机交给操作系统。</p>
</li>
</ol>

        <h3 id="7）Rewrite-压缩">
          <a href="#7）Rewrite-压缩" class="heading-link"><i class="fas fa-link"></i></a>7）Rewrite 压缩</h3>
      <p>当 <strong>AOF</strong> 文件 &gt;= 设置定文件大小后，会对 <strong>AOF</strong> 文件进行<font color="red">压缩重写</font></p>
<p>例：</p>
<figure class="highlight plain"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 我们实际执行的指令</span><br><span class="line">set k1 v1</span><br><span class="line">set k2 v2</span><br><span class="line"></span><br><span class="line">压缩后的</span><br><span class="line">set k1 v1 k2 v2</span><br></pre></td></tr></table></div></figure>

<p><font color="red">其实 AOF 的压缩重写，就是把一些命令重写为一条命令，不去关注过程，只关注最后的结果。</font></p>

        <h1 id="十二、Redis-主从复制">
          <a href="#十二、Redis-主从复制" class="heading-link"><i class="fas fa-link"></i></a>十二、Redis 主从复制</h1>
      
        <h2 id="1、什么是主从复制">
          <a href="#1、什么是主从复制" class="heading-link"><i class="fas fa-link"></i></a>1、什么是主从复制</h2>
      <p>主机数据更新后根据配置和策略，自动同步到备机的 <font color="red">master/slaver 机制</font>，  <font color="red"><strong>Master</strong> 以写为主，<strong>Slaver</strong> 以读为主</font>。</p>

        <h2 id="2、能干嘛">
          <a href="#2、能干嘛" class="heading-link"><i class="fas fa-link"></i></a>2、能干嘛</h2>
      <ul>
<li><p>读写分离，性能扩展。</p>
</li>
<li><p>容灾快速恢复</p>
<p>如果某一台从机出现问题，可以切换另一台从机。如果是主机出现问题，则可以通过集群来解决。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/48.png" alt="图片加载失败"></p>
</li>
</ul>

        <h2 id="3、主从配置">
          <a href="#3、主从配置" class="heading-link"><i class="fas fa-link"></i></a>3、主从配置</h2>
      <p>这里是在一台虚拟机中，通过不同端口来模拟多台服务器</p>
<ol>
<li><p>新建一个目录，名字自己定义就好了。</p>
</li>
<li><p>将我们原本的 <strong>redis.conf</strong> 复制到新创建的目录中。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/49.png" alt="图片加载失败"></p>
</li>
<li><p>创建三个配置文件，分别以端口进行区别，内容配置也要进行相应的修改</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/50.png" alt="图片加载失败"></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 引入基本的配置文件</span></span><br><span class="line">include /usr/local/myredis/redis.conf</span><br><span class="line"><span class="meta">#</span><span class="bash"> 重新配置的内容，可以覆盖基本配置中配置的</span></span><br><span class="line">pidfile /var/run/redis_6379.pid</span><br><span class="line">port 6379</span><br><span class="line">dbfilename dump6379.rdb</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>可以看到这里我们已经起来了这三个 <strong>Redis</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/51.png" alt="图片加载失败"></p>
</li>
<li><p>连接三台 <strong>Redis</strong> 并查看信息，可以看到三台 <strong>Redis</strong> 都是 <strong>master(主)</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/52.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/53.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/54.png" alt="图片加载失败"></p>
</li>
<li><p>配置主从关系：<strong>配从（库）不配主（库）</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 在从机中使用命令配置，ip：主机ip，port：主机端口</span></span><br><span class="line">slaveof ip port</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 取消从服务器配置，会重新变成主服务器</span></span><br><span class="line">slaveof no one</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>查看信息已经可以看到，角色（role）已经为从机（slave）</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/55.png" alt="图片加载失败"></p>
</li>
<li><p>测试</p>
<ul>
<li><p>在主机中新增一个 <strong>key</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/56.png" alt="图片加载失败"></p>
</li>
<li><p>在从机中查看</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/57.png" alt="图片加载失败"></p>
</li>
</ul>
<p><font color="red">注意：写操作只能在主机中进行，从机中只能进行读操作</font></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/58.png" alt="图片加载失败"></p>
</li>
</ol>

        <h2 id="4、主从复制的原理">
          <a href="#4、主从复制的原理" class="heading-link"><i class="fas fa-link"></i></a>4、主从复制的原理</h2>
      <ol>
<li>当从服务器（<strong>slave</strong>）连接上主服务器（<strong>master</strong>）之后，从服务器（<strong>slave</strong>）会向主服务器（<strong>master</strong>）发送进行数据同步的消息</li>
<li><strong>master</strong> 接到 <strong>slave</strong> 发送过来的同步消息后，把 <strong>master</strong> 的数据会持久化到 <strong>RDB</strong> 文件，把 <strong>RDB</strong> 文件发送给 <strong>slave</strong>，<strong>slave</strong> 拿到 <strong>RDB</strong> 文件进行读取</li>
<li><strong>master</strong> 每次进行写操作后，会和 <strong>slave</strong> 进行同步数据。</li>
</ol>
<p><font color="red">注意：</font></p>
<p>上面第 2 步是 <strong>slave</strong> 主动同步数据（全量复制），第 3 步是 <strong>master</strong> 主动同步数据（增量复制）</p>
<ul>
<li><strong>全量复制：</strong>从服务器（<strong>slave</strong>）主动发送消息同步数据</li>
<li><strong>增量复制：</strong>主服务器（<strong>master</strong>）将写操作命令传给从服务器（<strong>slave</strong>）进行数据同步</li>
</ul>

        <h2 id="5、一主二仆">
          <a href="#5、一主二仆" class="heading-link"><i class="fas fa-link"></i></a>5、一主二仆</h2>
      <p><strong>特点：</strong></p>
<ol>
<li>当某一台从服务器挂掉之后再重启，他重新变成一个主机，并不会恢复成原来的从服务器</li>
<li>当某一台冲服务器挂掉之后，主服务数据发生了变动，从服务器重启之后，重新设置成主服务的从服务器，那么他会将主服务器的数据复制过来</li>
<li>当主服务挂掉之后，从服务器还是从服务器，并且可以看到主服务器已经挂掉了（down），并不会上位变成主服务器。当主服务器重新启动之后，依旧是主服务器，两台从服务器还是他小弟，并且可以再信息中看到大哥的状态是启动的（up）</li>
</ol>
<p><strong>测试：</strong></p>
<ol>
<li><p><strong>shutdown</strong> 掉 6381，查看主服务器（6379） 的信息，我们可以看到主服务器信息中只有一台从服务器了</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/59.png" alt="图片加载失败"></p>
</li>
<li><p>我们在 主服务器（6379）中随意添加几条数据。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/62.png" alt="图片加载失败"></p>
</li>
<li><p>重新启动 6381，并查看信息，我们可以看到他重新变成了主服务器</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/60.png" alt="图片加载失败"></p>
</li>
<li><p>我们将 6381 重新设置成从服务器，并分别查看他和主服务器的信息，可以看到他已经变成了从服务器，而且主服务器的信息中显示有两台从服务器。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/61.png" alt="图片加载失败"></p>
</li>
<li><p>查看从服务器中的数据，可以看到和主服务器是一样的</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/63.png" alt="图片加载失败"></p>
</li>
</ol>

        <h2 id="6、薪火相传">
          <a href="#6、薪火相传" class="heading-link"><i class="fas fa-link"></i></a>6、薪火相传</h2>
      <p><strong>薪火相传</strong> 我们可以理解为 <strong>组织架构树</strong> 或者我们实际工作中<strong>项目经理、组长、组员</strong>这种结构。</p>
<p>就是说：</p>
<ul>
<li>6379 为主服务器</li>
<li>6380 是 6379 的从服务器</li>
<li>6381 是 6380 的服务器</li>
</ul>
<p>这样，6379 数据会同步给 6380 ，6380 再同步给 6381。</p>
<p><strong>缺点：</strong></p>
<p>当 6380 挂掉了，那么 6379 的数据也无法同步给 6381了。</p>
<p>这里可以自己进行测试一下，我这里就不实际进行操作了。</p>

        <h2 id="7、反客为主">
          <a href="#7、反客为主" class="heading-link"><i class="fas fa-link"></i></a>7、反客为主</h2>
      <p>其实这个就是我们上面提到的 <strong>slaveof no one</strong> 命令，可已将从机变为主机。</p>
<p><strong>缺点：</strong> 需要手动完成。</p>

        <h2 id="8、哨兵模式">
          <a href="#8、哨兵模式" class="heading-link"><i class="fas fa-link"></i></a>8、哨兵模式</h2>
      
        <h3 id="1）什么是哨兵模式">
          <a href="#1）什么是哨兵模式" class="heading-link"><i class="fas fa-link"></i></a>1）什么是哨兵模式</h3>
      <p><font color="red">反客为主的自动版</font>，能够后台监控主机是否故障，如果故障了，根据投票数自动将从库转换为主库。</p>
<p>其实就像是 <strong>zookeeper</strong> 集群的选举。<font color="#FFFFFF">农奴翻身把歌唱，噢耶！</font></p>

        <h3 id="2）如何使用">
          <a href="#2）如何使用" class="heading-link"><i class="fas fa-link"></i></a>2）如何使用</h3>
      <ol>
<li><p>设置为一主二仆/多仆模式</p>
</li>
<li><p>创建 <strong>sentinel.conf</strong> 文件，目录自定义，我们这里就放在和 <strong>redis6379.conf</strong> 同级的目录下了</p>
</li>
<li><p>配置哨兵，编写 <strong>sentinel.conf</strong> 配置文件内容</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> sentinel 哨兵</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> monitor 监控</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> mymaster 为监控对象起的服务器名称，其实就是为 master 主机起个别名</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 192.168.111.144 6379 主机 ip 和端口</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 1 至少有多少个哨兵同意迁移的数量，通俗的说就是：需要有多少个从机同意才能切换为主机，这里个人建议设置为从机数量的一半以上。类似于 zookeeper 的选举</span></span><br><span class="line">sentinel monitor mymaster 192.168.111.144 6379 1</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>启动哨兵，使用 <strong>redis-sentinel</strong> 启动</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/64.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/65.png" alt="图片加载失败"></p>
<p>注意，哨兵服务的默认端口为：26379</p>
</li>
<li><p>测试，关掉 6379，查看哨兵窗口变化</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/66.png" alt="图片加载失败"></p>
<p>这里通过控制台信息我们可以看到 6381 被选为了主服务器，6380 变成了 6381 的从机。</p>
<p>还有一个信息就是，6379 还在。那么当 6379 重新启动后会变成什么样呢？这里我们将 6379 重启，并查看信息。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/67.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/68.png" alt="图片加载失败"></p>
<p>通过上面的信息我们可以看到，6379 变成了 6381 的从机。</p>
</li>
<li><p>复制延时</p>
<p>哨兵模式的缺点，由于所有的写操作都是在 <strong>Master</strong> 上进行的，然后同步更新到 <strong>Slave</strong> 上，所以从 <strong>Master</strong> 同步到 <strong>Slave</strong> 会有一定的延迟，当系统很繁忙的时候，延迟问题会更加严重，<strong>Slave</strong> 机器数量的增加也会使这个问题更加严重。</p>
</li>
</ol>

        <h3 id="3）故障恢复">
          <a href="#3）故障恢复" class="heading-link"><i class="fas fa-link"></i></a>3）故障恢复</h3>
      <p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/69.png" alt="图片加载失败"></p>
<ul>
<li><p>优先级在 <strong>redis.conf</strong> 中默认：<strong>replica-priority 100</strong> ，值越小优先级越高</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/70.png" alt="图片加载失败"></p>
</li>
<li><p>偏移量是指获得原主机数据最全的</p>
</li>
<li><p>每个 <strong>Redis</strong> 实例启动后都会随机生成一个 40 位的 <strong>runid</strong>。</p>
</li>
</ul>

        <h3 id="4）springboot-主从复制">
          <a href="#4）springboot-主从复制" class="heading-link"><i class="fas fa-link"></i></a>4）springboot 主从复制</h3>
      <p>只需要在 <strong>yml</strong> 配置文件中进行相应配置即可：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/71.png" alt="图片加载失败"></p>
<p>服务启动出现了报错：</p>
<figure class="highlight java"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 哨兵哨兵命令返回少于2个节点!在Redis配置中至少应该定义两个哨兵。设置checkSentinelsList = false以避免此检查。</span></span><br><span class="line">SENTINEL SENTINELS command returns less than <span class="number">2</span> nodes! At least two sentinels should be defined in Redis configuration. Set checkSentinelsList = <span class="keyword">false</span> to avoid <span class="keyword">this</span> check.</span><br></pre></td></tr></table></div></figure>

<p>经过一番搜索并没有找到什么有用的，所以我又增加了两个哨兵@~@</p>
<ol>
<li><p>修改原有的 <strong>sentinel.conf</strong> 配置文件，并重命名为 <strong>sentinel6379.conf</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sentinel monitor mymaster 192.168.111.144 6379 1</span><br><span class="line">protected-mode no</span><br><span class="line">port 26379</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>新增两个配置文件，分别是：<strong>sentinel6380.conf</strong>，<strong>sentinel6381.conf</strong>，只需要修改一下 <strong>port</strong> ，分别是：26380，26381</p>
</li>
</ol>
<p>启动服务/测试类测试：</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/72.png" alt="图片加载失败"></p>
<p>执行后可以到 <strong>Redis</strong> 中看一下数据是不是已经存进去了。</p>
<p>参考：<span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/152462924">springboot+redis的sentinel实现哨兵模式(超详细)</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>

        <h1 id="十三、Redis-集群">
          <a href="#十三、Redis-集群" class="heading-link"><i class="fas fa-link"></i></a>十三、Redis 集群</h1>
      
        <h2 id="1、问题">
          <a href="#1、问题" class="heading-link"><i class="fas fa-link"></i></a>1、问题</h2>
      <ol>
<li>容量不够，<strong>redis</strong> 如何进行扩容？</li>
<li>并发写操作，<strong>redis</strong> 如何分摊？</li>
</ol>
<p>另外，主从模式，薪火相传模式，主机宕机，导致 <strong>ip</strong> 地址发生变化，应用程序中配置需要修改对应的主机地址、端口等信息。</p>
<p>之前通过代理主机来解决，但是 <strong>redis3.0</strong> 中提供了解决方案。就是 <font color="red">无中心化集群</font> 配置。</p>

        <h2 id="2、什么是集群？">
          <a href="#2、什么是集群？" class="heading-link"><i class="fas fa-link"></i></a>2、什么是集群？</h2>
      <ul>
<li><strong>Redis</strong> 集群实现了对 <strong>Redis</strong> 的水平扩容，即启动 <strong>N</strong> 个 <strong>Redis</strong> 节点，将这个数据库分布存储在这 <strong>N</strong> 个节点中，每个节点存储总数据的 <strong>1/N</strong>。</li>
<li><strong>Redis</strong> 集群通过分区<strong>（partition）</strong>来提供一定程度的可用性<strong>（availability）</strong>：即使集群中有一部分节点失效或者无法进行通讯，集群也可以继续处理命令请求。</li>
</ul>

        <h2 id="3、Redis-集群的搭建">
          <a href="#3、Redis-集群的搭建" class="heading-link"><i class="fas fa-link"></i></a>3、Redis 集群的搭建</h2>
      <p>这里我们还是在同一台虚拟机中以不同的端口的方式来模拟搭建，依旧是 <strong>主从复制</strong> 中用到的目录就可以。</p>
<p>创建六个实例分别是：<strong>6379、6380、6381、6389、6390、6391</strong>（三主三从）。</p>
<ol>
<li><p>删除掉之前测试产生的 <strong>dump、aof</strong> 文件。</p>
</li>
<li><p>我们在 <strong>redis_6379.conf</strong> 的基础上配置基本信息</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/73.png" alt="图片加载失败"></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/74.png" alt="图片加载失败"></p>
</li>
<li><p>在配置文件中增加集群相关配置</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/75.png" alt="图片加载失败"></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">include /usr/local/myredis/redis.conf</span><br><span class="line">pidfile &quot;/var/run/redis_6379.pid&quot;</span><br><span class="line">port 6379</span><br><span class="line">dbfilename &quot;dump6379.rdb&quot;</span><br><span class="line">logfile &quot;/usr/local/myredis/redis_err_6379.log&quot;</span><br><span class="line">daemonize yes</span><br><span class="line">dir &quot;/usr/local/myredis&quot;</span><br><span class="line"><span class="meta">#</span><span class="bash"> 开启集群</span></span><br><span class="line">cluster-enabled yes</span><br><span class="line"><span class="meta">#</span><span class="bash"> 指定集群节点配置文件</span></span><br><span class="line">cluster-config-file nodes_6379.conf</span><br><span class="line"><span class="meta">#</span><span class="bash"> 设定节点失联时间（毫秒），超时后集群自动进入主从切换</span></span><br><span class="line">cluster-node-timeout 15000</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>删除6380 6381 两个配置文件，并将我们刚才修改好的配置文件在复制出5份。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/76.png" alt="图片加载失败"></p>
</li>
<li><p>修改复制出来的那几份文件，修改相应的端口</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 可以使用替换进行操作</span></span><br><span class="line">vim redis6380.conf</span><br><span class="line">:%s/6379/6380</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/77.png" alt="图片加载失败"></p>
</li>
<li><p>启动 6 个 <strong>Redis</strong> 服务，并查看节点配置文件是否正确生成了</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/78.png" alt="图片加载失败"></p>
</li>
<li><p>将 6 个节点合成一个集群</p>
<ul>
<li><p>进入到 <strong>Redis</strong> 安装目录的 <strong>src</strong> 中，或者是解压的目录中的 <strong>src</strong> 中。</p>
</li>
<li><p>使用命令进行合体</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 注意下面的命令只能在安装目录的 src 下才可以使用，使用 ip，不要使用 127.0.0.1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> --cluster create 集群创建</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> --cluster-replicas 1 采用最简单的方式配置集群，一主一从，正好三组。前 3 为主机，后 3 为从机</span></span><br><span class="line">redis-cli --cluster create --cluster-replicas 1 192.168.111.144:6379 192.168.111.144:6380 192.168.111.144:6381 192.168.111.144:6389 192.168.111.144:6390 192.168.111.144:6391</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>执行命令</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/79.png" alt="图片加载失败"></p>
<p>执行命令后会展示分配的一些信息，并会询问我们是否接受这种分配方式，我们输入 <strong>yes</strong></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/80.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
<li><p>连接</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> -c 采用集群策略连接，设置数据会自动切换到相应的写主机</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 连接任何一个都可以，例如6379/6380/6381，会自动切换到写主机</span></span><br><span class="line">redis-cli -c -p 6379</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>查看集群节点信息：<strong>cluster nodes</strong></p>
<p>我们可以在信息中看到哪一台是主机，哪一台是从机，和对应的主从。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/81.png" alt="图片加载失败"></p>
</li>
</ol>

        <h2 id="4、Redis-cluster-如何分配这六个节点？">
          <a href="#4、Redis-cluster-如何分配这六个节点？" class="heading-link"><i class="fas fa-link"></i></a>4、Redis cluster 如何分配这六个节点？</h2>
      <ul>
<li>一个集群至少要有三个主节点</li>
<li>选项 <strong>–cluster-replicas 1</strong> 表示我们希望为集群中的每个主节点创建一个从节点。</li>
<li>分配原则尽量保证每个主数据库运行在不同的 <strong>IP</strong> 地址，每个从库和主库不在一个 <strong>IP</strong> 地址上。</li>
</ul>

        <h2 id="5、什么是-slots-插槽">
          <a href="#5、什么是-slots-插槽" class="heading-link"><i class="fas fa-link"></i></a>5、什么是 slots(插槽)?</h2>
      <p>通俗的来说就像是 洞 ，每个洞都可以放入东西。</p>
<ul>
<li><p>一个 <strong>Redis</strong> 集群包含 16384 个插槽（hash slot），数据库中的每个键都属于这 16384 个插槽中的其中一个。</p>
</li>
<li><p>每个主节点都有他负责的一定范围的插槽，可以再节点信息中看到。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/82.png" alt="图片加载失败"></p>
</li>
<li><p>集群会使用 <strong>CRC16(key)%16384</strong> 来计算 <strong>key</strong> 属于哪个插槽，其中的 <strong>CRC16(key)</strong> 语句用于计算键 <strong>key</strong> 的 <strong>CRC16</strong> 校验和。</p>
</li>
</ul>

        <h2 id="6、集群数据的新增与查询">
          <a href="#6、集群数据的新增与查询" class="heading-link"><i class="fas fa-link"></i></a>6、集群数据的新增与查询</h2>
      <ol>
<li><p>新增（单个key/value、多个key/value）</p>
<ul>
<li><p>下图可见，根据key计算除了插槽，并存储到了相应的主机中，并切换到了相应的主机</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/83.png" alt="图片加载失败"></p>
</li>
<li><p>多个 key/value 新增</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 错误方式,多个 key 不能同时插入一个插槽</span></span><br><span class="line">mset name lucy age 20 addr china</span><br><span class="line"><span class="meta">#</span><span class="bash">err:CROSSSLOT Keys <span class="keyword">in</span> request don<span class="string">&#x27;t hash to the same slot</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">正确方式，使用 &#123;组名&#125; 的方式新增数据</span></span><br><span class="line"><span class="meta">#</span><span class="bash">这样就会根据&#123;&#125;中的组名去计算插槽</span></span><br><span class="line">mset name&#123;user&#125; lucy age&#123;user&#125; 20 addr&#123;user&#125; china</span><br></pre></td></tr></table></div></figure>
</li>
</ul>
</li>
<li><p>查询集群中的值</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 获取 key 在集群中的插槽位置：cluster keyslot key</span></span><br><span class="line">cluster keyslot k1</span><br><span class="line">result: 12706</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取插槽位置中有几个值，只能插槽所在的主机中用，否则返回 0</span></span><br><span class="line">cluster countkeysinslot 12706</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取指定插槽中count个 key，cluster get keysinslot slot count</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 获取 12706 这个插槽中的 key，获取 10 个</span></span><br><span class="line">cluster getkeysinslot 12706 10</span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h2 id="7、故障恢复">
          <a href="#7、故障恢复" class="heading-link"><i class="fas fa-link"></i></a>7、故障恢复</h2>
      <ol>
<li><p>如果主节点下线，从节点能否自动提升为主节点？注意：<font color="red">15 秒超时</font></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/84.png" alt="图片加载失败"></p>
<p>从上图可以看到，6379 下线之后，6380 在 15 秒之后提升为主节点了。</p>
</li>
<li><p>下线的主节点恢复之后，主从关系如何？</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/85.png" alt="图片加载失败"></p>
<p>从上图可以看到，下线的主节点恢复后变成了从机。</p>
</li>
<li><p>如果某一段插槽的主从都挂掉了（集群中的某一组主从挂掉），那么这个集群是否还能继续使用？</p>
<p>根据 <strong>redis.conf</strong> 中 <strong>cluster-require-full-coverage</strong> 配置而变化的：</p>
<ul>
<li>如果 <strong>cluster-require-full-coverage</strong> 为 <strong>yes</strong> ，那么，整个集群都挂掉。</li>
<li>如果 <strong>cluster-require-full-coverage</strong> 为 <strong>no</strong> ，那么就只有该主从不能用，也无法存储。</li>
</ul>
</li>
</ol>

        <h2 id="8、springboot-集群的配置">
          <a href="#8、springboot-集群的配置" class="heading-link"><i class="fas fa-link"></i></a>8、springboot 集群的配置</h2>
      <ol>
<li><p>修改 <strong>yml</strong> 配置文件</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/86.png" alt="图片加载失败"></p>
</li>
<li><p>测试类测试</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/87.png" alt="图片加载失败"></p>
</li>
</ol>
<p>这样简单的配置就好了，我这里没有报错一切顺利，因为我也没用过，所以这些应该是很基础的配置。</p>

        <h2 id="9、Redis-集群的好处与不足">
          <a href="#9、Redis-集群的好处与不足" class="heading-link"><i class="fas fa-link"></i></a>9、Redis 集群的好处与不足</h2>
      <ol>
<li>好处：<ul>
<li>实现扩容</li>
<li>分摊压力</li>
<li>无中心配置，相对简单</li>
</ul>
</li>
<li>不足<ul>
<li>多键操作是不被支持的</li>
<li>多键的 <strong>Redis</strong> 事务是不被支持的。<strong>lua</strong> 脚本不被支持。</li>
<li>由于集群方案出现的较晚，很多公司已经采用了其他的集群方案，而代理或者客户端分片的方案想要 <strong>迁移</strong> 至 <strong>redis cluster</strong>，需要整体迁移，而不是逐步过渡，复杂难度大</li>
</ul>
</li>
</ol>

        <h1 id="十四、Redis-应用问题解决">
          <a href="#十四、Redis-应用问题解决" class="heading-link"><i class="fas fa-link"></i></a>十四、Redis 应用问题解决</h1>
      
        <h2 id="1、缓存穿透">
          <a href="#1、缓存穿透" class="heading-link"><i class="fas fa-link"></i></a>1、缓存穿透</h2>
      <ol>
<li><p>什么是 <strong>缓存穿透</strong></p>
<p><strong>缓存穿透：</strong> 就是大量的请求 <font color="red">访问缓存，获取不存在的数据</font>，这个时候就会去请求数据库（<font color="red">数据库中也不存在</font>），导致数据库瘫痪或错误、宕掉等。</p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/88.png" alt="图片加载失败"></p>
</li>
<li><p>出现场景</p>
<p>一般出现在一下两种场景中：</p>
<ul>
<li><strong>redis</strong> 中查询不到数据</li>
<li>出现很多非正常 <strong>url</strong> 访问</li>
</ul>
</li>
<li><p>解决方案</p>
<ul>
<li><p><font color="red">对空值缓存</font></p>
<p>如果查询返回的数据为空（不管数据是不是存在），我们仍然把这个空结果（null）进行缓存，设置空结果的过期时间会很短，最长不会超过五分钟。</p>
</li>
<li><p><font color="red">设置可以访问的名单（白名单）</font></p>
<p>使用 <strong>bitmaps</strong> 类型定义一个可以访问的名单，名单 <strong>id</strong> 作为 <strong>bitmaps</strong> 的偏移量，每次访问和 <strong>bitmaps</strong> 里面的 <strong>id</strong> 进行比较，如果访问的 <strong>id</strong> 不在 <strong>bitmaps</strong> 中，进行拦截，不允许访问。</p>
</li>
<li><p><font color="red">采用布隆过滤器</font></p>
<p>这个底层其实就是一个 <strong>bitmaps</strong> ，只不过做了相应的封装等。</p>
<p>其实就是检索一个元素是否在一个集合中。</p>
<p>优点：空间效率和查询时间都远超一般的算法</p>
<p>缺点：有一定的误识别率和删除困难</p>
</li>
<li><p><font color="red">进行实时监控</font></p>
<p>当发现 <strong>Redis</strong> 的命中率开始急速降低，需要排查访问对象和访问的数据，和运维人员配合，可以设置黑名单限制服务。</p>
</li>
</ul>
</li>
</ol>

        <h2 id="2、缓存击穿">
          <a href="#2、缓存击穿" class="heading-link"><i class="fas fa-link"></i></a>2、缓存击穿</h2>
      <ol>
<li><p>什么是 <strong>缓存击穿</strong></p>
<p><strong>缓存击穿：</strong> key 对应的数据在数据库中存在，但是在 <strong>redis</strong> 中过期，此时若有大量并发请求过来，这些请求发现缓存过期一般都会从后端 <strong>DB</strong> 加载数据并回设到缓存，这个时候并发的请求可能会瞬间把后端 <strong>DB</strong> 压垮</p>
<p><font color="red">注意：这里指的是某个 <strong>key</strong> 过期了，大量访问使用这个 <strong>key</strong>。并不是出现大量的 <strong>key</strong> 过期</font></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/89.png" alt="图片加载失败"></p>
</li>
<li><p>解决方案</p>
<ul>
<li><p><font color="red">预先设置热门数据</font></p>
<p>在 <strong>redis</strong> 高峰访问之前，把一些热门数据提前存入到 <strong>Redis</strong> 中，并加大这些热门数据 <strong>key</strong> 的时长</p>
</li>
<li><p><font color="red">实时调整</font></p>
<p>现场监控那些数据热门，实时调整 <strong>key</strong> 的过期时长 </p>
</li>
<li><p><font color="red">使用锁</font></p>
<p><img src="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/90.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
</ol>

        <h2 id="3、缓存雪崩">
          <a href="#3、缓存雪崩" class="heading-link"><i class="fas fa-link"></i></a>3、缓存雪崩</h2>
      <ol>
<li><p>什么是 <strong>缓存雪崩</strong></p>
<p><strong>缓存雪崩：</strong> 在极少时间段内，查询大量 <strong>key</strong> 的集中过期情况。</p>
</li>
<li><p>解决方案</p>
<ul>
<li><p><font color="red">构建多级缓存架构</font></p>
<p><strong>nginx</strong> 缓存 + <strong>Redis</strong> 缓存  + 其他缓存（<strong>ehcache</strong> 等）</p>
</li>
<li><p><font color="red">使用锁或队列</font></p>
<p>用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写，从而避免失效时大量的并发请求落到底层存储系统上。不适合高并发情况。</p>
</li>
<li><p><font color="red">设置过期标志更新缓存</font></p>
<p>记录缓存数据是否过期（设置提前量），如果过期会触发通知另外的线程在后台去更新实际 <strong>key</strong> 的缓存</p>
</li>
<li><p><font color="red">将缓存失效时间分散开</font></p>
<p>比如我们可以再原有的失效时间基础上增加一个随机值，比如 1-5 分钟随机，这样每一个缓存的过期时间的重复率就会降低，就很难引发集体失效的事件。</p>
</li>
</ul>
</li>
</ol>

        <h2 id="4、分布式锁">
          <a href="#4、分布式锁" class="heading-link"><i class="fas fa-link"></i></a>4、分布式锁</h2>
      
        <h3 id="1）什么是-分布式锁">
          <a href="#1）什么是-分布式锁" class="heading-link"><i class="fas fa-link"></i></a>1）什么是 分布式锁</h3>
      <p>个人理解 <strong>分布式锁</strong> 就是应用在集群、分布式服务中。因为原单体单机部署的系统演化成分布式集群系统，由于分布式系统多线程、多进程且分布在不同的机器上，这样原来的单机部署情况下的并发锁策略就失效了，我们就需要一种跨 <strong>JVM</strong> 的互斥机制（锁）来控制共享资源的访问</p>

        <h3 id="2）实现方式">
          <a href="#2）实现方式" class="heading-link"><i class="fas fa-link"></i></a>2）实现方式</h3>
      <ul>
<li><p>基于数据库实现</p>
</li>
<li><p>基于缓存（<strong>Redis</strong> 等）</p>
<p>性能好</p>
</li>
<li><p>基于 <strong>zookeeper</strong></p>
<p>可靠性高</p>
</li>
</ul>

        <h3 id="3）使用-redis实现分布式锁">
          <a href="#3）使用-redis实现分布式锁" class="heading-link"><i class="fas fa-link"></i></a>3）使用 redis实现分布式锁</h3>
      <p>其实就是 <strong>setnx key value</strong> 来设置一个 <strong>key</strong> 作为锁，释放锁就是删除掉这个 <strong>key</strong>。</p>
<ul>
<li><p>问题一：假如现在出现了别的情况，例如：加锁之后程序报错或由于别的原因没有释放该怎么办呢？</p>
<p>解决方式就是设置一个过期时间</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">set key_lock 1</span><br><span class="line">exprie key_lock 10</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>问题二：如果在设置过期时间的时候服务器突然死掉了或者由于一些其他原因设置失败了怎么办？</p>
<p>解决方式就是加锁的同时设置过期时间</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 这个命令在上面说过，他的意思就是：新增一个 key 并设置他的时间，只有在这个 key 不存在的时候才能设置成功</span></span><br><span class="line">set kye_lock 1 EX 10 NX</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>问题三：误删问题</p>
<p>这个可以通过添加 <strong>UUID</strong> 等方式解决，在上面的 <span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://sunyubk.github.io/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/#3%EF%BC%89%E8%B6%85%E5%8D%96%E5%92%8C%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3">秒发案例的超卖问题中</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span> 中已经解决过了。</p>
</li>
</ul>

        <h1 id="案例">
          <a href="#案例" class="heading-link"><i class="fas fa-link"></i></a>案例</h1>
      
        <h2 id="案例一、">
          <a href="#案例一、" class="heading-link"><i class="fas fa-link"></i></a>案例一、</h2>
      <p>场景：</p>
<ol>
<li>一亿个用户，用户有频繁登录的，也有不经常登录的</li>
<li>如何记录用户的登录信息</li>
<li>如何查询活跃用户，[如： 连续登录的]</li>
</ol>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 以位图的方式来解决</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 用户的登录状态以 0/1来表示</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 初始值 一亿个用户都没有登陆过，设置第3,5,7位用户在周一登录过</span></span><br><span class="line">setbit mon 100000000 0</span><br><span class="line">setbit mon 3 1</span><br><span class="line">setbit mon 5 1</span><br><span class="line">setbit mon 7 1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置第3,4,8位用户在周二登录过</span></span><br><span class="line">setbit tue 100000000 0</span><br><span class="line">setbit tue 3 1</span><br><span class="line">setbit tue 4 1</span><br><span class="line">setbit tue 8 1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 设置第3,6,9位用户在周三登录过</span></span><br><span class="line">setbit wed 100000000 0</span><br><span class="line">setbit wed 3 1</span><br><span class="line">setbit wed 6 1</span><br><span class="line">setbit wed 9 1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 按位与运算</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> res 为比较后返回的结果集</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 例子：0100</span></span><br><span class="line"><span class="meta">#</span><span class="bash">      0101 </span></span><br><span class="line"><span class="meta">#</span><span class="bash">      0110</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> and 返回结果集是0100，位图的同一个位置都一样，则返回的是1，否则返回0</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> or  返回结果集是0111，位图的同一个位置有一个是1，则返回1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> </span></span><br><span class="line"><span class="meta">#</span><span class="bash">使用一下命令则可以得到res,三天都登录了的用户</span></span><br><span class="line">bitop and res mon tue wed</span><br></pre></td></tr></table></div></figure>


</div><footer class="post-footer"><div class="post-ending ending"><div class="ending__text">------ 本文结束，感谢您的阅读 ------</div></div><div class="post-copyright copyright"><div class="copyright-author"><span class="copyright-author__name">本文作者: </span><span class="copyright-author__value"><a href="http://yoursite.com">孙宇</a></span></div><div class="copyright-link"><span class="copyright-link__name">本文链接: </span><span class="copyright-link__value"><a href="http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/">http://yoursite.com/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/</a></span></div><div class="copyright-notice"><span class="copyright-notice__name">版权声明: </span><span class="copyright-notice__value">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" rel="external nofollow" target="_blank">BY-NC-SA</a> 许可协议。转载请注明出处！</span></div></div><div class="post-tags"><span class="post-tags-item"><span class="post-tags-item__icon"><i class="fas fa-tag"></i></span><a class="post-tags-item__link" href="http://yoursite.com/tags/Redis/">Redis</a></span></div><nav class="post-paginator paginator"><div class="paginator-prev"><a class="paginator-prev__link" href="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/"><span class="paginator-prev__icon"><i class="fas fa-angle-left"></i></span><span class="paginator-prev__text">Docker学习</span></a></div><div class="paginator-next"><a class="paginator-next__link" href="/2020/09/07/SpringCloud-%E5%AD%A6%E4%B9%A0/"><span class="paginator-prev__text">SpringCloud 学习</span><span class="paginator-next__icon"><i class="fas fa-angle-right"></i></span></a></div></nav></footer></div></div><div class="comments" id="comments"><div id="gitalk-container"></div></div></div><div class="sidebar-wrap" id="sidebar-wrap"><aside class="sidebar" id="sidebar"><div class="sidebar-nav"><span class="sidebar-nav-toc current">文章目录</span><span class="sidebar-nav-ov">站点概览</span></div><section class="sidebar-toc"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%80%E3%80%81%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-text">
          一、环境准备</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E5%AE%89%E8%A3%85"><span class="toc-text">
          二、安装</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E9%85%8D%E7%BD%AE"><span class="toc-text">
          三、配置</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9B%9B%E3%80%81%E5%90%AF%E5%8A%A8%E4%B8%8E%E8%BF%9E%E6%8E%A5"><span class="toc-text">
          四、启动与连接</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%94%E3%80%81%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4"><span class="toc-text">
          五、操作命令</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C"><span class="toc-text">
          1、基础操作</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E5%88%A0%E9%99%A4"><span class="toc-text">
          2）删除</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E4%BF%AE%E6%94%B9"><span class="toc-text">
          3）修改</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%EF%BC%89%E6%9F%A5%E8%AF%A2"><span class="toc-text">
          4）查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5%EF%BC%89%E5%90%84%E7%A7%8D%E6%9F%A5%E8%AF%A2"><span class="toc-text">
          5）各种查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6%EF%BC%89key-%E7%A7%BB%E5%8A%A8"><span class="toc-text">
          6）key 移动</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-%EF%BC%89key-%E9%80%92%E5%A2%9E-%E5%87%8F"><span class="toc-text">
          7 ）key 递增&#x2F;减</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8%EF%BC%89key-%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">
          8）key 的生命周期</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9%EF%BC%89%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%9C%8916%E4%B8%AA"><span class="toc-text">
          9）切换数据库，默认有16个</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10%EF%BC%89%E6%B8%85%E7%A9%BA%E6%95%B0%E6%8D%AE%E5%BA%93"><span class="toc-text">
          10）清空数据库</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-text">
          2、各种数据类型的操作</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1%E3%80%81string%EF%BC%88%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%89%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          2-1、string（字符串）类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-1"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89%E5%88%A0%E9%99%A4"><span class="toc-text">
          3）删除</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%EF%BC%89%E5%81%8F%E7%A7%BB%E9%87%8F"><span class="toc-text">
          4）偏移量</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2%E3%80%81list%EF%BC%88%E5%88%97%E8%A1%A8%EF%BC%89%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          2-2、list（列表）类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-2"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-1"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89-%E5%88%A0%E9%99%A4%EF%BC%88%E5%BC%B9%E5%87%BA%EF%BC%89"><span class="toc-text">
          3） 删除（弹出）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%EF%BC%89%E5%89%AA%E5%88%87"><span class="toc-text">
          4）剪切</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5%EF%BC%89%E5%BC%B9%E5%87%BA%E5%B9%B6%E6%8F%92%E5%85%A5"><span class="toc-text">
          5）弹出并插入</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3%E3%80%81set%EF%BC%88%E9%9B%86%E5%90%88%EF%BC%89%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%97%A0%E5%BA%8F"><span class="toc-text">
          2-3、set（集合）类型，无序</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-3"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-2"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89%E5%88%A0%E9%99%A4%EF%BC%88%E5%BC%B9%E5%87%BA%EF%BC%89"><span class="toc-text">
          3）删除（弹出）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%EF%BC%89%E6%9B%B4%E5%A4%9A"><span class="toc-text">
          4）更多</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4%E3%80%81Hash%EF%BC%88%E5%93%88%E5%B8%8C%EF%BC%89%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          2-4、Hash（哈希）类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-4"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-3"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89%E5%88%A0%E9%99%A4-1"><span class="toc-text">
          3）删除</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%EF%BC%89%E6%9B%B4%E5%A4%9A-1"><span class="toc-text">
          4）更多</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5%E3%80%81zset-order-set-%E6%9C%89%E5%BA%8F%E9%9B%86%E5%90%88"><span class="toc-text">
          2-5、zset(order set) 有序集合</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-5"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-4"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89%E5%88%A0%E9%99%A4-2"><span class="toc-text">
          3）删除</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%EF%BC%89-%E6%9B%B4%E5%A4%9A"><span class="toc-text">
          4） 更多</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AD%E3%80%81%E5%8F%91%E5%B8%83%E5%92%8C%E8%AE%A2%E9%98%85"><span class="toc-text">
          六、发布和订阅</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E5%8F%91%E5%B8%83%E5%92%8C%E8%AE%A2%E9%98%85"><span class="toc-text">
          1、什么是发布和订阅</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E5%8F%91%E5%B8%83%E5%92%8C%E8%AE%A2%E9%98%85%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%A4%BA%E4%BE%8B"><span class="toc-text">
          2、发布和订阅命令行示例</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%83%E3%80%81%E6%96%B0%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          七、新数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81Bitmaps%EF%BC%88%E4%BD%8D%E6%93%8D%E4%BD%9C%EF%BC%89"><span class="toc-text">
          1、Bitmaps（位操作）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81HyperLogLog%EF%BC%88%E5%9F%BA%E6%95%B0%E7%BB%9F%E8%AE%A1%EF%BC%89"><span class="toc-text">
          2、HyperLogLog（基数统计）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-6"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-5"><span class="toc-text">
          2）查询</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E6%9B%B4%E5%A4%9A"><span class="toc-text">
          3）更多</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81Geospatial%EF%BC%88%E5%9C%B0%E7%90%86%E4%BF%A1%E6%81%AF%E7%9A%84%E7%BC%A9%E5%86%99%EF%BC%89"><span class="toc-text">
          3、Geospatial（地理信息的缩写）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E6%96%B0%E5%A2%9E-7"><span class="toc-text">
          1）新增</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E6%9F%A5%E8%AF%A2-6"><span class="toc-text">
          2）查询</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AB%E3%80%81Jedis-%E6%93%8D%E4%BD%9C"><span class="toc-text">
          八、Jedis 操作</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81Jedis-%E8%BF%9E%E6%8E%A5%E6%B5%8B%E8%AF%95"><span class="toc-text">
          1、Jedis 连接测试</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E6%B5%8B%E8%AF%95%E7%9B%B8%E5%85%B3%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          2、测试相关数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89String-%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          1）String 类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89List-%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          2）List 类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89Set-%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          3）Set 类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%EF%BC%89Hash-%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          4）Hash 类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5%EF%BC%89ZSet-%E7%B1%BB%E5%9E%8B"><span class="toc-text">
          5）ZSet 类型</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E6%A8%A1%E6%8B%9F%E5%8F%91%E9%80%81%E9%AA%8C%E8%AF%81%E7%A0%81"><span class="toc-text">
          3、模拟发送验证码</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%94%9F%E6%88%90%E9%AA%8C%E8%AF%81%E7%A0%81%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-text">
          1）创建一个生成验证码的方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E5%88%9B%E5%BB%BA%E7%94%9F%E6%88%90%E9%AA%8C%E8%AF%81%E7%A0%81%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-text">
          2）创建生成验证码的方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E5%88%9B%E5%BB%BA%E6%A0%A1%E9%AA%8C%E9%AA%8C%E8%AF%81%E7%A0%81%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-text">
          3）创建校验验证码的方法</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B9%9D%E3%80%81SpringBoot-%E6%95%B4%E5%90%88-Redis"><span class="toc-text">
          九、SpringBoot 整合 Redis</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%9C%A8-pom-%E6%96%87%E4%BB%B6%E4%B8%AD%E5%BC%95%E5%85%A5%E7%9B%B8%E5%85%B3%E4%BE%9D%E8%B5%96"><span class="toc-text">
          1、在 pom 文件中引入相关依赖</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81application-yml-%E9%85%8D%E7%BD%AE-redis-%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE"><span class="toc-text">
          2、application.yml 配置 redis 相关配置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E9%85%8D%E7%BD%AE-redis-%E9%85%8D%E7%BD%AE%E7%B1%BB"><span class="toc-text">
          3、配置 redis 配置类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81redis-%E5%B7%A5%E5%85%B7%E7%B1%BB"><span class="toc-text">
          4、redis 工具类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E7%BC%96%E5%86%99-controller-%E6%B5%8B%E8%AF%95"><span class="toc-text">
          5、编写 controller 测试</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%81%E3%80%81Redis-%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81%E6%9C%BA%E5%88%B6"><span class="toc-text">
          十、Redis 事务和锁机制</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C"><span class="toc-text">
          1、基本操作</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E3%80%81Multi%E3%80%81Exec%E3%80%81Discard"><span class="toc-text">
          1）、Multi、Exec、Discard</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E4%BA%8B%E5%8A%A1%E7%9A%84%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="toc-text">
          2）事务的错误处理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E4%BA%8B%E5%8A%A1%E5%86%B2%E7%AA%81%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-text">
          2、事务冲突的问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E4%BE%8B%E5%AD%90"><span class="toc-text">
          3、例子</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-text">
          1）解决方案</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-%E6%82%B2%E8%A7%82%E9%94%81"><span class="toc-text">
          1. 悲观锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-%E4%B9%90%E8%A7%82%E9%94%81"><span class="toc-text">
          2.乐观锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-watch-key-key%E2%80%A6-%E5%91%BD%E4%BB%A4"><span class="toc-text">
          3.watch key [key…] 命令</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81Redis-%E4%BA%8B%E5%8A%A1%E4%B8%89%E7%89%B9%E6%80%A7"><span class="toc-text">
          4、Redis 事务三特性</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E7%A7%92%E6%9D%80%E6%A1%88%E4%BE%8B"><span class="toc-text">
          5、秒杀案例</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E5%9F%BA%E6%9C%AC%E5%AE%9E%E7%8E%B0"><span class="toc-text">
          1）基本实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89ab%E5%B7%A5%E5%85%B7%E6%A8%A1%E6%8B%9F%E5%B9%B6%E5%8F%91"><span class="toc-text">
          2）ab工具模拟并发</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1%EF%BC%89%E5%AE%89%E8%A3%85-httpd-tools"><span class="toc-text">
          2-1）安装 httpd-tools</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2%EF%BC%89%E5%91%BD%E4%BB%A4%E5%8F%8A%E5%B8%B8%E7%94%A8%E5%8F%82%E6%95%B0"><span class="toc-text">
          2-2）命令及常用参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-3%EF%BC%89%E6%B5%8B%E8%AF%95"><span class="toc-text">
          2-3）测试</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E8%B6%85%E5%8D%96%E5%92%8C%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3"><span class="toc-text">
          3）超卖和连接超时问题解决</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1%EF%BC%89%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E9%97%AE%E9%A2%98"><span class="toc-text">
          3-1）连接超时问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2%EF%BC%89%E8%B6%85%E5%8D%96%E9%97%AE%E9%A2%98"><span class="toc-text">
          3-2）超卖问题</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-setnx-%E8%A7%A3%E5%86%B3"><span class="toc-text">
          1.setnx 解决</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-Redisson-%E8%A7%A3%E5%86%B3"><span class="toc-text">
          2.Redisson 解决</span></a></li></ol></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%81%E4%B8%80%E3%80%81Redis-%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-text">
          十一、Redis 持久化</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81RDB"><span class="toc-text">
          1、RDB</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E4%BB%80%E4%B9%88%E6%98%AF-RDB"><span class="toc-text">
          1）什么是 RDB</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E5%A4%87%E4%BB%BD%E6%98%AF%E5%A6%82%E4%BD%95%E6%89%A7%E8%A1%8C%E7%9A%84"><span class="toc-text">
          2）备份是如何执行的</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E5%A4%87%E4%BB%BD%E6%96%87%E4%BB%B6%E4%BD%8D%E7%BD%AE%E4%B8%8E%E5%A4%87%E4%BB%BD%E8%A7%84%E5%88%99"><span class="toc-text">
          3）备份文件位置与备份规则</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%EF%BC%89%E5%91%BD%E4%BB%A4-save-VS-bgsave"><span class="toc-text">
          4）命令 save VS bgsave</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81AOF"><span class="toc-text">
          2、AOF</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E4%BB%80%E4%B9%88%E6%98%AF-AOF"><span class="toc-text">
          1）什么是 AOF</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89AOF-%E6%8C%81%E4%B9%85%E5%8C%96%E6%B5%81%E7%A8%8B"><span class="toc-text">
          2）AOF 持久化流程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89AOF-%E9%BB%98%E8%AE%A4%E4%B8%8D%E5%BC%80%E5%90%AF"><span class="toc-text">
          3）AOF 默认不开启</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%EF%BC%89AOF-%E5%92%8C-RDB-%E5%90%8C%E6%97%B6%E5%BC%80%E5%90%AF%EF%BC%8CRedis-%E5%90%AC%E8%B0%81%E7%9A%84%EF%BC%9F"><span class="toc-text">
          4）AOF 和 RDB 同时开启，Redis 听谁的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5%EF%BC%89AOF-%E6%96%87%E4%BB%B6%E6%8D%9F%E5%9D%8Fxiuf"><span class="toc-text">
          5）AOF 文件损坏xiuf</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6%EF%BC%89AOF-%E5%90%8C%E6%AD%A5%E9%A2%91%E7%8E%87%E8%AE%BE%E7%BD%AE"><span class="toc-text">
          6）AOF 同步频率设置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7%EF%BC%89Rewrite-%E5%8E%8B%E7%BC%A9"><span class="toc-text">
          7）Rewrite 压缩</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%81%E4%BA%8C%E3%80%81Redis-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6"><span class="toc-text">
          十二、Redis 主从复制</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6"><span class="toc-text">
          1、什么是主从复制</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E8%83%BD%E5%B9%B2%E5%98%9B"><span class="toc-text">
          2、能干嘛</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E4%B8%BB%E4%BB%8E%E9%85%8D%E7%BD%AE"><span class="toc-text">
          3、主从配置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E7%9A%84%E5%8E%9F%E7%90%86"><span class="toc-text">
          4、主从复制的原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E4%B8%80%E4%B8%BB%E4%BA%8C%E4%BB%86"><span class="toc-text">
          5、一主二仆</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E8%96%AA%E7%81%AB%E7%9B%B8%E4%BC%A0"><span class="toc-text">
          6、薪火相传</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E5%8F%8D%E5%AE%A2%E4%B8%BA%E4%B8%BB"><span class="toc-text">
          7、反客为主</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81%E5%93%A8%E5%85%B5%E6%A8%A1%E5%BC%8F"><span class="toc-text">
          8、哨兵模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E4%BB%80%E4%B9%88%E6%98%AF%E5%93%A8%E5%85%B5%E6%A8%A1%E5%BC%8F"><span class="toc-text">
          1）什么是哨兵模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8"><span class="toc-text">
          2）如何使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E6%95%85%E9%9A%9C%E6%81%A2%E5%A4%8D"><span class="toc-text">
          3）故障恢复</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%EF%BC%89springboot-%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6"><span class="toc-text">
          4）springboot 主从复制</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%81%E4%B8%89%E3%80%81Redis-%E9%9B%86%E7%BE%A4"><span class="toc-text">
          十三、Redis 集群</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E9%97%AE%E9%A2%98"><span class="toc-text">
          1、问题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E9%9B%86%E7%BE%A4%EF%BC%9F"><span class="toc-text">
          2、什么是集群？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81Redis-%E9%9B%86%E7%BE%A4%E7%9A%84%E6%90%AD%E5%BB%BA"><span class="toc-text">
          3、Redis 集群的搭建</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81Redis-cluster-%E5%A6%82%E4%BD%95%E5%88%86%E9%85%8D%E8%BF%99%E5%85%AD%E4%B8%AA%E8%8A%82%E7%82%B9%EF%BC%9F"><span class="toc-text">
          4、Redis cluster 如何分配这六个节点？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF-slots-%E6%8F%92%E6%A7%BD"><span class="toc-text">
          5、什么是 slots(插槽)?</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E9%9B%86%E7%BE%A4%E6%95%B0%E6%8D%AE%E7%9A%84%E6%96%B0%E5%A2%9E%E4%B8%8E%E6%9F%A5%E8%AF%A2"><span class="toc-text">
          6、集群数据的新增与查询</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81%E6%95%85%E9%9A%9C%E6%81%A2%E5%A4%8D"><span class="toc-text">
          7、故障恢复</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E3%80%81springboot-%E9%9B%86%E7%BE%A4%E7%9A%84%E9%85%8D%E7%BD%AE"><span class="toc-text">
          8、springboot 集群的配置</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9%E3%80%81Redis-%E9%9B%86%E7%BE%A4%E7%9A%84%E5%A5%BD%E5%A4%84%E4%B8%8E%E4%B8%8D%E8%B6%B3"><span class="toc-text">
          9、Redis 集群的好处与不足</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8D%81%E5%9B%9B%E3%80%81Redis-%E5%BA%94%E7%94%A8%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3"><span class="toc-text">
          十四、Redis 应用问题解决</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F"><span class="toc-text">
          1、缓存穿透</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF"><span class="toc-text">
          2、缓存击穿</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9"><span class="toc-text">
          3、缓存雪崩</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81"><span class="toc-text">
          4、分布式锁</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1%EF%BC%89%E4%BB%80%E4%B9%88%E6%98%AF-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81"><span class="toc-text">
          1）什么是 分布式锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2%EF%BC%89%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F"><span class="toc-text">
          2）实现方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3%EF%BC%89%E4%BD%BF%E7%94%A8-redis%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81"><span class="toc-text">
          3）使用 redis实现分布式锁</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E6%A1%88%E4%BE%8B"><span class="toc-text">
          案例</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A1%88%E4%BE%8B%E4%B8%80%E3%80%81"><span class="toc-text">
          案例一、</span></a></li></ol></li></ol></section><!-- ov = overview--><section class="sidebar-ov hide"><div class="sidebar-ov-author"><div class="sidebar-ov-author__avatar"><img class="sidebar-ov-author__avatar_img" src="/images/img_head.jpg" alt="avatar"></div><p class="sidebar-ov-author__text">悠闲时光</p></div><div class="sidebar-ov-state"><a class="sidebar-ov-state-item sidebar-ov-state-item--posts" href="/archives/"><div class="sidebar-ov-state-item__count">14</div><div class="sidebar-ov-state-item__name">归档</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--categories" href="/categories/"><div class="sidebar-ov-state-item__count">10</div><div class="sidebar-ov-state-item__name">分类</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--tags" href="/tags/"><div class="sidebar-ov-state-item__count">7</div><div class="sidebar-ov-state-item__name">标签</div></a></div><div class="sidebar-ov-cc"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" target="_blank" rel="noopener" data-popover="知识共享许可协议" data-popover-pos="up"><img src="/images/cc-by-nc-sa.svg"></a></div></section><div class="sidebar-reading"><div class="sidebar-reading-info"><span class="sidebar-reading-info__text">你已阅读了 </span><span class="sidebar-reading-info__num">0</span></div><div class="sidebar-reading-line"></div></div></aside></div><div class="clearfix"></div></div></main><footer class="footer" id="footer"><div class="footer-inner"><div><span>Copyright © 2021</span><span class="footer__icon"><i class="fas fa-heart"></i></span><span>孙宇</span></div><div><span>由 <a href="http://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a> 强力驱动</span><span> v5.0.2</span><span class="footer__devider">|</span><span>主题 - <a href="https://github.com/liuyib/hexo-theme-stun/" title="Stun" target="_blank" rel="noopener">Stun</a></span><span> v2.0.0-rc.0</span></div></div></footer><div class="loading-bar" id="loading-bar"><div class="loading-bar__progress"></div></div><div class="back2top" id="back2top"><span class="back2top__icon"><i class="fas fa-rocket"></i></span></div></div><div class="search-mask"></div><div class="search-popup"><span class="search-close"></span><div class="search-input"><input placeholder="搜索文章（支持多关键词，请用空格分隔）"></div><div class="search-results"></div></div><script src="https://cdn.jsdelivr.net/npm/jquery@v3.4.1/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.ui.min.js"></script><script src="https://cdn.jsdelivr.net/npm/ribbon.js@latest/dist/ribbon.min.js" size="120" alpha="0.6" zIndex="-1"></script><script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-canvas-nest@latest/canvas-nest.min.js" color="1,0,0" opacity="0.6" count="99" zIndex="-1"></script><script>function initSearch() {
  var isXML = true;
  var search_path = 'search.json';

  if (!search_path) {
    search_path = 'search.xml';
  } else if (/json$/i.test(search_path)) {
    isXML = false;
  }

  var path = '/' + search_path;
  $.ajax({
    url: path,
    dataType: isXML ? 'xml' : 'json',
    async: true,
    success: function (res) {
      var datas = isXML ? $('entry', res).map(function () {
        // 将 XML 转为 JSON
        return {
          title: $('title', this).text(),
          content: $('content', this).text(),
          url: $('url', this).text()
        };
      }).get() : res;
      var $input = $('.search-input input');
      var $result = $('.search-results');
      // 搜索对象（标题、内容）的权重，影响显示顺序
      var WEIGHT = { title: 100, content: 1 };
      var searchPost = function () {
        var searchText = $input.val().toLowerCase().trim();
        // 根据空白字符分隔关键字
        var keywords = searchText.split(/[\s]+/);
        // 搜索结果
        var matchPosts = [];

        // 有多个关键字时，将原文字整个保存下来
        if (keywords.length > 1) {
          keywords.push(searchText);
        }
        // 防止未输入字符时搜索
        if (searchText.length > 0) {
          datas.forEach(function (data) {
            var isMatch  = false;
            // 没有标题的文章使用预设的 i18n 变量代替
            var title = (data.title && data.title.trim()) || '[ 文章无标题 ]';
            var titleLower = title && title.toLowerCase();
            // 删除 HTML 标签 和 所有空白字符
            var content = data.content && data.content.replace(/<[^>]+>/g, '');
            var contentLower = content && content.toLowerCase();
            // 删除重复的 /
            var postURL = data.url && decodeURI(data.url).replace(/\/{2,}/g, '/');
            // 标题中匹配到的关键词
            var titleHitSlice = [];
            // 内容中匹配到的关键词
            var contentHitSlice = [];

            keywords.forEach(function (keyword) {
              /**
              * 获取匹配的关键词的索引
              * @param {String} keyword 要匹配的关键字
              * @param {String} text 原文字
              * @param {Boolean} caseSensitive 是否区分大小写
              * @param {Number} weight 匹配对象的权重。权重大的优先显示
              * @return {Array}
              */
              function getIndexByword (word, text, caseSensitive, weight) {
                if (!word || !text) {
                  return [];
                };

                var startIndex = 0; // 每次匹配的开始索引
                var index = -1;     // 匹配到的索引值
                var result = [];    // 匹配结果

                if (!caseSensitive) {
                  word = word.toLowerCase();
                  text = text.toLowerCase();
                }

                while((index = text.indexOf(word, startIndex)) !== -1) {
                  var hasMatch = false;
                  // 索引位置相同的关键词，保留长度较长的
                  titleHitSlice.forEach(function (hit) {
                    if (hit.index === index && hit.word.length < word.length) {
                      hit.word = word;
                      hasMatch = true;
                    }
                  });
                  startIndex = index + word.length;
                  !hasMatch && result.push({ index: index, word: word, weight: weight });
                }
                return result;
              }
              titleHitSlice = titleHitSlice.concat(getIndexByword(keyword, titleLower, false, WEIGHT.title));
              contentHitSlice = contentHitSlice.concat(getIndexByword(keyword, contentLower, false, WEIGHT.content));
            });

            var hitTitle = titleHitSlice.length;
            var hitContent = contentHitSlice.length;

            if (hitTitle > 0 || hitContent > 0) {
              isMatch = true;
            }
            if (isMatch) {
              ;[titleHitSlice, contentHitSlice].forEach(function (hit) {
                // 按照匹配文字的索引的递增顺序排序
                hit.sort(function (left, right) {
                  return left.index - right.index;
                });
              });
              /**
              * 给文本中匹配到的关键词添加标记，从而进行高亮显示
              * @param {String} text 原文本
              * @param {Array} hitSlice 匹配项的索引信息
              * @param {Number} start 开始索引
              * @param {Number} end 结束索引
              * @return {String}
              */
              function highlightKeyword (text, hitSlice, start, end) {
                if (!text || !hitSlice || !hitSlice.length) {
                  return;
                }

                var result = '';
                var startIndex = start;
                var endIndex = end;
                hitSlice.forEach(function (hit) {
                  if (hit.index < startIndex) {
                    return;
                  }

                  var hitWordEnd = hit.index + hit.word.length;
                  result += text.slice(startIndex, hit.index);
                  result += '<b>' + text.slice(hit.index, hitWordEnd) + '</b>';
                  startIndex = hitWordEnd;
                });
                result += text.slice(startIndex, endIndex);
                return result;
              }

              var postData = {};
              // 文章总的搜索权重
              var postWeight = titleHitSlice.length * WEIGHT.title + contentHitSlice.length * WEIGHT.content;
              // 标记匹配关键词后的标题
              var postTitle = highlightKeyword(title, titleHitSlice, 0, title.length) || title;
              // 标记匹配关键词后的内容
              var postContent;
              // 显示内容的长度
              var SHOW_WORD_LENGTH = 200;
              // 命中关键词前的字符显示长度
              var SHOW_WORD_FRONT_LENGTH = 20;
              var SHOW_WORD_END_LENGTH = SHOW_WORD_LENGTH - SHOW_WORD_FRONT_LENGTH;

              // 截取匹配的第一个字符，前后共 200 个字符来显示
              if (contentHitSlice.length > 0) {
                var firstIndex = contentHitSlice[0].index;
                var start = firstIndex > SHOW_WORD_FRONT_LENGTH ? firstIndex - SHOW_WORD_FRONT_LENGTH : 0;
                var end = firstIndex + SHOW_WORD_END_LENGTH;
                postContent = highlightKeyword(content, contentHitSlice, start, end);
              } else { // 未匹配到内容，直接截取前 200 个字符来显示
                postContent = content.slice(0, SHOW_WORD_LENGTH);
              }
              postData.title = postTitle;
              postData.content = postContent;
              postData.url = postURL;
              postData.weight = postWeight;
              matchPosts.push(postData);
            }
          });
        }

        var resultInnerHtml = '';
        if (matchPosts.length) {
          // 按权重递增的顺序排序，使权重大的优先显示
          matchPosts.sort(function (left, right) {
            return right.weight - left.weight;
          });
          resultInnerHtml += '<ul>';
          matchPosts.forEach(function (post) {
            resultInnerHtml += '<li><a class="search-results-title" href="' + post.url + '">';
            resultInnerHtml += post.title;
            resultInnerHtml += '</a><div class="search-results-content">';
            resultInnerHtml += post.content;
            resultInnerHtml += '</div></li>';
          });
          resultInnerHtml += '</ul>';
        } else {
          resultInnerHtml += '<div class="search-results-none"><i class="far fa-meh"></i></div>';
        }
        $result.html(resultInnerHtml);
      };
      $input.on('input', searchPost);
      $input.on('keyup', function (e) {
        if (e.keyCode === Stun.utils.codeToKeyCode('Enter')) {
          searchPost();
        }
      });
    }
  });
}

function closeSearch () {
  $('body').css({ overflow: 'auto' });
  $('.search-popup').css({ display: 'none' });
  $('.search-mask').css({ display: 'none' });
}

window.addEventListener('DOMContentLoaded', function () {
  Stun.utils.pjaxReloadLocalSearch = function () {
    $('.header-nav-search').on('click', function (e) {
      e.stopPropagation();
      $('body').css('overflow', 'hidden');
      $('.search-popup')
        .velocity('stop')
        .velocity('transition.expandIn', {
          duration: 300,
          complete: function () {
            $('.search-popup input').focus();
          }
        });
      $('.search-mask')
        .velocity('stop')
        .velocity('transition.fadeIn', {
          duration: 300
        });

      initSearch();
    });
    $('.search-mask, .search-close').on('click', function () {
      closeSearch();
    });
    $(document).on('keydown', function (e) {
      // Escape <=> 27
      if (e.keyCode === Stun.utils.codeToKeyCode('Escape')) {
        closeSearch();
      }
    });
  };

  Stun.utils.pjaxReloadLocalSearch();
}, false);</script><script src="https://cdn.jsdelivr.net/npm/gitalk@latest/dist/gitalk.min.js"></script><script src="https://cdn.jsdelivr.net/npm/js-md5@latest/src/md5.min.js"></script><script>function loadGitalk () {
  if (!document.getElementById('gitalk-container')) {
    return;
  }

  var gitalk = new Gitalk({
    id: md5(window.location.pathname.slice(1)),
    clientID: '6ca09daabba4f7147cee',
    clientSecret: 'ded593f333a1a88bfb1a5e39e8227c3afc71e08f',
    repo: 'sunyubk.github.io',
    owner: 'sunyubk',
    admin: ['sunyubk'],
    distractionFreeMode: 'true',
    language: 'zh-CN'
  });
  gitalk.render('gitalk-container');
}

if (false) {
  loadGitalk();
} else {
  window.addEventListener('DOMContentLoaded', loadGitalk, false);
}</script><script src="/js/utils.js?v=2.0.0-rc.0"></script><script src="/js/stun-boot.js?v=2.0.0-rc.0"></script><script src="/js/scroll.js?v=2.0.0-rc.0"></script><script src="/js/header.js?v=2.0.0-rc.0"></script><script src="/js/sidebar.js?v=2.0.0-rc.0"></script><script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/live2dw/assets/shizuku.model.json"},"display":{"position":"left","width":250,"height":500},"mobile":{"show":false},"log":false});</script></body></html>